Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
48.55% covered (warning)
48.55%
4523 / 9317
52.63% covered (warning)
52.63%
50 / 95
CRAP
0.00% covered (danger)
0.00%
0 / 1
WaitingController
48.51% covered (warning)
48.51%
4516 / 9310
52.63% covered (warning)
52.63%
50 / 95
1061022.38
0.00% covered (danger)
0.00%
0 / 1
 beforeFilter
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
1 / 1
1
 checkHash
100.00% covered (success)
100.00%
92 / 92
100.00% covered (success)
100.00%
1 / 1
2
 index
65.88% covered (success)
65.88%
195 / 296
0.00% covered (danger)
0.00%
0 / 1
239.05
 checkProperProfile
40.00% covered (warning)
40.00%
2 / 5
0.00% covered (danger)
0.00%
0 / 1
4.94
 detail
69.63% covered (success)
69.63%
658 / 945
0.00% covered (danger)
0.00%
0 / 1
2344.47
 getStrengthRating
95.00% covered (success)
95.00%
19 / 20
0.00% covered (danger)
0.00%
0 / 1
6
 getLessonHistory
90.32% covered (success)
90.32%
56 / 62
0.00% covered (danger)
0.00%
0 / 1
23.48
 getPrimaryDetails
96.30% covered (success)
96.30%
26 / 27
0.00% covered (danger)
0.00%
0 / 1
6
 getFavCount
95.45% covered (success)
95.45%
21 / 22
0.00% covered (danger)
0.00%
0 / 1
5
 getAlbum
97.83% covered (success)
97.83%
45 / 46
0.00% covered (danger)
0.00%
0 / 1
5
 arrangeTeacherRecommendList
61.97% covered (success)
61.97%
44 / 71
0.00% covered (danger)
0.00%
0 / 1
71.12
 checkReservation
88.46% covered (success)
88.46%
23 / 26
0.00% covered (danger)
0.00%
0 / 1
10.15
 start
76.92% covered (success)
76.92%
20 / 26
0.00% covered (danger)
0.00%
0 / 1
12.49
 teacherReserveList
89.21% covered (success)
89.21%
339 / 380
0.00% covered (danger)
0.00%
0 / 1
127.76
 updateChapterOptions
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 result
97.64% covered (success)
97.64%
124 / 127
0.00% covered (danger)
0.00%
0 / 1
7
 loadMoreComments
100.00% covered (success)
100.00%
90 / 90
100.00% covered (success)
100.00%
1 / 1
25
 output
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 isCanCancel
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
5
 convertString
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getTextbookOption
100.00% covered (success)
100.00%
85 / 85
100.00% covered (success)
100.00%
1 / 1
12
 getAllTextbookOption
99.40% covered (success)
99.40%
332 / 334
0.00% covered (danger)
0.00%
0 / 1
122
 saveTextbookPreset
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
1 / 1
16
 callLessonAlertandStartButton
90.80% covered (success)
90.80%
523 / 576
0.00% covered (danger)
0.00%
0 / 1
371.58
 loadMoreSelfReviews
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
5
 getUserReviews
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
1
 getReserveAndCancelled
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
3
 triggerOrangeButton
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
5
 deleteLessonOnair
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
11
 getTeacherOnlineList
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
3
 getSearchCondition
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
1 / 1
2
 getApologyList
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
1
 limitwarning
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
5
 updatedScheduleColor
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
4
 getAvatarDisabledDates
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
4
 sp_counselor
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 counselor
90.00% covered (success)
90.00%
162 / 180
0.00% covered (danger)
0.00%
0 / 1
38.37
 customersupport
0.00% covered (danger)
0.00%
0 / 152
0.00% covered (danger)
0.00%
0 / 1
756
 counselingGetDisabledDates
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 counselorSlots
0.00% covered (danger)
0.00%
0 / 130
0.00% covered (danger)
0.00%
0 / 1
2070
 avatarSlots
0.00% covered (danger)
0.00%
0 / 219
0.00% covered (danger)
0.00%
0 / 1
4290
 counselingLimit
94.38% covered (success)
94.38%
84 / 89
0.00% covered (danger)
0.00%
0 / 1
22.09
 avatarLimit
100.00% covered (success)
100.00%
73 / 73
100.00% covered (success)
100.00%
1 / 1
19
 checkCounselingReservationNow
77.59% covered (success)
77.59%
45 / 58
0.00% covered (danger)
0.00%
0 / 1
11.13
 spDetail
0.00% covered (danger)
0.00%
0 / 262
0.00% covered (danger)
0.00%
0 / 1
1892
 spAvatarDetail
0.00% covered (danger)
0.00%
0 / 157
0.00% covered (danger)
0.00%
0 / 1
702
 avatar_detail
0.00% covered (danger)
0.00%
0 / 629
0.00% covered (danger)
0.00%
0 / 1
21170
 getTeacherReviews
100.00% covered (success)
100.00%
79 / 79
100.00% covered (success)
100.00%
1 / 1
29
 favoriteTextbookCategoryForReview
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
1 / 1
14
 teacherAvatarStatus
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
5
 checkMaintenanceForAlert
100.00% covered (success)
100.00%
32 / 32
100.00% covered (success)
100.00%
1 / 1
4
 isAvatar
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
15
 counselorLatestLessonHistory
100.00% covered (success)
100.00%
139 / 139
100.00% covered (success)
100.00%
1 / 1
4
 avatarLatestLessonHistory
100.00% covered (success)
100.00%
133 / 133
100.00% covered (success)
100.00%
1 / 1
6
 userAvailPopularTeacher
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
5
 userValidForSSBEDT
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
5
 loadLiveLessonTeacher
100.00% covered (success)
100.00%
60 / 60
100.00% covered (success)
100.00%
1 / 1
27
 sms_questionnaire
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 avatar_sms_questionnaire
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 checkCounselorTeacherButtonStatus
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
1 / 1
14
 emergencyLesson
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
7
 teacherBadgeList
100.00% covered (success)
100.00%
83 / 83
100.00% covered (success)
100.00%
1 / 1
16
 avatarBadgeList
100.00% covered (success)
100.00%
79 / 79
100.00% covered (success)
100.00%
1 / 1
16
 teacherOccupation
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 teacherFeatures
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
 getSelfReviews
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
4
 getGenerationRating
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
7
 getGenerationRatingAPI
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
7
 getUserMemo
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
1 / 1
5
 getReservationCancellationBreakdown
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 getActiveCampaign
0.00% covered (danger)
0.00%
0 / 535
0.00% covered (danger)
0.00%
0 / 1
21756
 getActiveCampaignStampData
0.00% covered (danger)
0.00%
0 / 177
0.00% covered (danger)
0.00%
0 / 1
272
 showCampaignModal
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
5
 generateTextbookTeacherRecommendAjax
97.01% covered (success)
97.01%
65 / 67
0.00% covered (danger)
0.00%
0 / 1
18
 setUpAppreciationSelectionModalElementAjax
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
6
 sendTeacherAppreciationAjax
100.00% covered (success)
100.00%
69 / 69
100.00% covered (success)
100.00%
1 / 1
20
 ajaxUpdateSystemTrouble
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
9
 reportProblem
50.77% covered (warning)
50.77%
33 / 65
0.00% covered (danger)
0.00%
0 / 1
29.18
 getApppreciationModal
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
72
 getAppreciationStatus
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
42
 getEvaluationDetail
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
42
 resetLessonReviewModal
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 finishOnlineLesson
0.00% covered (danger)
0.00%
0 / 272
0.00% covered (danger)
0.00%
0 / 1
7310
 getCounselorLessonHistory
0.00% covered (danger)
0.00%
0 / 56
0.00% covered (danger)
0.00%
0 / 1
342
 speakingTestAttendance
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
42
 getRegion
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
56
 getResidenceData
29.17% covered (danger)
29.17%
7 / 24
0.00% covered (danger)
0.00%
0 / 1
45.54
 countTeacherReservedLessons
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 getLiveCouponResult
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
2
 checkLessonStartButtonNormal
0.00% covered (danger)
0.00%
0 / 671
0.00% covered (danger)
0.00%
0 / 1
112560
 checkLessonStartButtonAvatar
0.00% covered (danger)
0.00%
0 / 653
0.00% covered (danger)
0.00%
0 / 1
94556
 checkLessonStartButtonCounselor
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
30
 checkLessonStartButtonCS
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
72
 updateLessonSystemTrouble
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
20
 setAppreciationModalFinish
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3App::uses('AppController', 'Controller');
4App::uses('MyPageController', 'Controller');
5App::uses('SpTeacherController', 'Controller');
6App::uses('myArray', 'Lib');
7App::import('Controller', 'Textbook');
8App::uses('AwsFileServer', 'Lib');
9App::uses('Sanitize', 'Utility');
10
11class WaitingController extends AppController{
12    public $uses = array(
13        'Teacher',
14        'LessonOnair',
15        'LessonSchedule',
16        'LessonScheduleCancel',
17        'LessonLog',
18        'User',
19        'UsersDetail',
20        'UsersCourses',
21        'UsersTicket',
22        'UsersPoint',
23        'ShiftWorkOff',
24        'ShiftWorkOn',
25        'UsersClassEvaluation',
26        'UsersLessonsCountMinus',
27        'DefineMaster',
28        'UsersFavorite',
29        'UserTable',
30        'TeacherFeature',
31        'UsersLastViewedTextbook',
32        'TeacherImage',
33        'TeacherStatus',
34        'TextbookCategory',
35        'Payment',
36        'TextbookCourseConnect',
37        'CountryCode',
38        'PhoneVerifyCheckLog',
39        'CommonTeacherStatus',
40        'LessonOnairsLog',
41        'Textbook',
42        'TeacherBadge',
43        'TeacherCourseBadge',
44        'ShiftWorkHideDate',
45        'UsersFavorite',
46        'CounselingTable',
47        'Counseling',
48        'TeacherDetail',
49        'Timezone',
50        'TeacherWeeklyRating',
51        'PopularTeacherCampaignPeriod',
52        'BlockList',
53        'Avatar',
54        'HomeBasedRankBasicAmountLog',
55        'HomeBasedRankBasicAmount',
56        'UsersMemo',
57        'GlobalTextbookCategory',
58        'TeacherRankCoin',
59        'UserTextbookFavorite',
60        'UserSearchCondition',
61        'UsersTextbookInfo',
62        'Corporate',
63        'TeacherStudentConnection',
64        'TextbookConnect',
65        'TeacherStudentConnection',
66        'TeacherFeatureRating',
67        'ChatHistory',
68        'TeacherTextbookStat',
69        'LessonOnairsViewer',
70        'FeatureRatingItem',
71        'UsersFavoriteCategoriesTeacher',
72        'LessonOnairsLogTimeExtension',
73        'LessonOnairsViewersLog',
74        'UsersTextbookInfo',
75        'UsersFavoriteCategories',
76        'UserFeatureRatingLastVoted',
77        'TeacherDetails',
78        'UserFirstLesson',
79        'AppreciationMessage',
80        'UsersClassEvaluationFeatureRating',
81        'ViewersClassEvaluation',
82        'TeacherCoinBox',
83        'LessonOnairsLogTable',
84        'LessonBookmark',
85        'CampaignPcBanner',
86        'ReservationCoin',
87        'CountryRegion',
88        'CampaignInstructor',
89        'CampaignTagControl',
90        'ProhibitedWord',
91        'TitleThresholdTeacher',
92        'ViewerFeatureRatingLastVoted',
93        'PlanTeacherCategoryBlock'
94    );
95
96    public $helpers = array('Html', 'Form');
97    public $selfReviewLimit = 10;
98    public $components = array('Cookie'); //NC-3096 add cookie
99    public $defaultMemoryLimit = null;
100    public $blockMemberSettings = [];
101    public function beforeFilter() {
102        parent::beforeFilter();
103        //NC-3096 cookies
104        $this->Cookie->name = 'searchTeacherForm';
105        $this->Cookie->time = 86400 ;  // 1 day
106        $this->Cookie->domain = $_SERVER['SERVER_NAME'];
107
108        $allowActionArr = array(
109            'index',
110            'detail',
111            'avatar_detail',
112            'avatarSlots',
113            'teacherReserveList',
114            'loadMoreComments',
115            'isShiftWorkCancelled',
116            'callLessonAlertandStartButton',
117            'counselor',
118            'sp_counselor',
119            'counselorSlots',
120            'checkCounselingReservationNow',
121            'teacherAvatarStatus',
122            'getTeacherReviews',
123            'loadLiveLessonTeacher',
124            'limitwarning',
125            'isCanCancel',
126            'teacherBadgeList',
127            'teacherOccupation',
128            'teacherFeatures',
129            'getSelfReviews',
130            'getGenerationRating',
131            'getReservationCancellationBreakdown',
132            'getAlbum',
133            'getFavCount',
134            'getLessonHistory',
135            'getStrengthRating',
136            'getGenerationRatingAPI',
137            'avatarBadgeList',
138            'getPrimaryDetails',
139            'finishOnlineLesson',
140            'speakingTestAttendance',
141            'getRegion',
142            'countTeacherReservedLessons',
143            'checkLessonStartButtonNormal',
144            'checkLessonStartButtonAvatar'
145        );
146
147        $phoneNumbers = $this->CountryCode->getCountryCodesWithSmsAuth();
148        $this->set('phoneNumbers', $phoneNumbers);
149
150        $this->Auth->allow($allowActionArr);
151        //Timezone timedifference
152        $this->set('timeDiffSecond', $this->timeDiffSecond);
153        $this->defaultMemoryLimit = ini_get("memory_limit");
154        $this->blockMemberSettings = $this->PlanTeacherCategoryBlock->getPlanTeacherCategoryBlock($this->sharedUserData['User']);
155    }
156
157    private function checkHash($table , $chatHash) { //returns data if chat_hash exist
158        $fields = array(
159            $table.'.id',
160            $table.'.teacher_id',
161            $table.'.user_id',
162            $table.'.start_time',
163            $table.'.end_time',
164            $table.'.lesson_type', // NC-3824
165            $table.'.lesson_finish', // NC-3824,
166            $table.'.created', // NC-3824
167            $table.'.user_agent',
168            $table.'.lesson_system_trouble',
169            $table.'.connect_id', // NC-5884
170            $table.'.live_lesson_flg',
171            $table.'.connect_id',
172            $table.'.lesson_schedule_id',
173            $table.'.counselor_flag',
174            $table.'.textbook_category_id',
175            'teacher.id',
176            'teacher.name',
177            'teacher.jp_name',
178            'teacher.image_url',
179            'teacher.home_flg', // NC-3824
180            'teacher.rank_coin_id', // NC-3824
181            'teacher.first_lesson_date', // NC-3824
182            'teacher.promote_date', // NC-3824
183            'TeacherDetail.referrer_id', // NC-3824
184            'teacher.counseling_flg', //NC-4589
185            'teacher.avatar_id',
186            'teacher.avatar_flg',
187            'teacher.avatar_parent_flg',
188            'User.nickname',
189            'User.created',
190            'User.fail_flg',
191            'User.charge_flg',
192            'User.birthday',
193            'User.birthday_show_flg',
194            'Connect.id',
195            'Connect.category_id',
196            'Connect.textbook_id',
197            'User.network_review_flg',
198            'User.textbook_review_flg',
199            'User.teacher_review_flg',
200            'User.next_textbook_flg',
201            'User.lesson_review_flg'
202        );
203
204        if ($table == 'LessonOnairsLog') {
205            array_push($fields, 'LessonOnairsLog.onair_id');
206        }
207
208        $data = array(  
209        'conditions' => 
210              array(
211                $table.'.chat_hash' => $chatHash
212               ),  
213        'joins' =>
214                  array(
215                    array(
216                        'table' => 'teachers',
217                        'alias' => 'teacher',
218                        'type' => 'left',
219                        'foreignKey' => false,
220                        'conditions' => array(
221                            'teacher.id ='.$table.'.teacher_id'
222                        )
223                    ),        
224                    array(
225                        'table' => 'users',
226                        'alias' => 'User',
227                        'type' => 'left',
228                        'conditions' => array(
229                            'User.id = '.$table.'.user_id'
230                        )
231                    ),
232                    array(
233                        'table' => 'textbook_connects',
234                        'alias' => 'Connect',
235                        'type' => 'left',
236                        'conditions' => array(
237                            'Connect.id = '.$table.'.connect_id'
238                        )
239                    ),
240                    array( // NC-3824
241                        'table' => 'teacher_details',
242                        'alias' => 'TeacherDetail',
243                        'type' => 'left',
244                        'conditions' => array(
245                            'TeacherDetail.teacher_id = '.$table.'.teacher_id'
246                        )
247                    )
248                ),
249
250        'fields' => $fields,                
251        'order' => array($table.'.id' => 'DESC')            
252        );
253
254        return $data;
255    }
256
257    /**
258 * @api {get} /user/:language/waiting index()
259 * @apiName index
260 * @apiGroup Waiting
261 * @apiDescription Retrieves the index page for the waiting area in Native Camp. It returns various information about the user, teachers, and campaigns.
262 *
263 * @apiParam {String} language The language code for the page.
264 * 
265 * @apiSuccess {Object[]} allBanners The list of campaign banners.
266 * @apiSuccess {String} allBanners.id The ID of the banner.
267 * @apiSuccess {String} allBanners.campaign_url The URL of the campaign.
268 * @apiSuccess {String} allBanners.start The start date of the campaign.
269 * @apiSuccess {String} allBanners.end The end date of the campaign.
270 * @apiSuccess {String} allBanners.image_url The image URL of the campaign.
271 * @apiSuccess {String} allBanners.event_tracking_tag The event tracking tag of the campaign.
272 * @apiSuccess {String} allBanners.display_position The display position of the campaign.
273 * @apiSuccess {Object} searchCount The count of saved search conditions.
274 * @apiSuccess {Object} userpoint The user points.
275 * @apiSuccess {String} localizeDir The localization directory.
276 * @apiSuccess {Object} selectOptions The select options for the teacher search.
277 * @apiSuccess {Object} selectOptions.availability The availability options.
278 * @apiSuccess {Object} selectOptions.classification The classification options.
279 * @apiSuccess {String} headtext The head text for the page.
280 * @apiSuccess {Object[]} badges The list of badges.
281 * @apiSuccess {Boolean} isLoggedIn Indicates if the user is logged in.
282 * @apiSuccess {Object} userData The user data.
283 * @apiSuccess {Object} userData.User The user object.
284 * @apiSuccess {String} userData.User.id The ID of the user.
285 * @apiSuccess {String} userData.User.currency_code The currency code of the user.
286 * @apiSuccess {String} userData.User.card_company The card company of the user.
287 * @apiSuccess {Object} userDataObj The user data object.
288 * @apiSuccess {Number} paymentPlanId The payment plan ID of the user.
289 * @apiSuccess {Number} userLang The language ID of the user.
290 * @apiSuccess {Object[]} seriesSpecialArr The list of special series.
291 * @apiSuccess {Object} seriesSelected The selected series.
292 * @apiSuccess {Object} counselor The counselor object.
293 * @apiSuccess {String} counselor.name The name of the counselor.
294 * @apiSuccess {String} counselor.jp_name The Japanese name of the counselor.
295 * @apiSuccess {String} counselor.image_url The image URL of the counselor.
296 * @apiSuccess {String} counselor.country_name The country name of the counselor.
297 * @apiSuccess {Boolean} isHide Indicates if the counselor is hidden.
298 * @apiSuccess {Object[]} favId The list of favorite teacher IDs.
299 * @apiSuccess {Object[]} teacherFavs The list of favorite teachers with colors.
300 * @apiSuccess {Object[]} teacherFavsColors The list of favorite teacher colors.
301 * @apiSuccess {Object[]} avatarActiveId The list of active avatar IDs.
302 * @apiSuccess {Boolean} teddyFav Indicates if the teddy avatar is favorited.
303 * @apiSuccess {Object[]} occupationData The list of teacher occupations.
304 * @apiSuccess {Object} counselorLampStatus The counselor lamp status.
305 * @apiSuccess {Boolean} hideCouselorFromMember Indicates if the counselor information should be hidden from the member.
306 * @apiSuccess {Boolean} is_lite_plan_user Indicates if the user is on a lite plan.
307 * @apiSuccess {Object[]} teacherList The list of teachers.
308 * @apiSuccess {Object[]} regions The list of regions.
309 * @apiSuccess {Object[]} coinData The list of coin data.
310 * @apiSuccess {Object} searchData The search data.
311 * @apiSuccess {Boolean} isLogin Indicates if the user is logged in.
312 * @apiSuccess {Number} savedConditionsCount The count of saved search conditions.
313 * @apiSuccess {Object} preset The preset textbook information.
314 * @apiSuccess {Object} searchCondition The search condition.
315 * @apiSuccess {Object[]} featureFilter The list of feature filters.
316 * @apiSuccess {Object} user The user object.
317 * @apiSuccess {String} user.id The ID of the user.
318 * @apiSuccess {String} user.name The name of the user.
319 * @apiSuccess {String} disconnectionChatHash The disconnection chat hash.
320 * @apiSuccess {Object[]} coins The list of coins.
321 * @apiSuccess {Object} campaignTagSearch The campaign tag search status.
322 *
323 * @apiSuccessExample {json} Success-Response:
324 *     {
325 *         "allBanners": [
326 *             {
327 *                 "id": "1",
328 *                 "campaign_url": "http://example.com/campaign",
329 *                 "start": "2023-12-01",
330 *                 "end": "2023-12-31",
331 *                 "image_url": "http://example.com/image.jpg",
332 *                 "event_tracking_tag": "tag1",
333 *                 "display_position": "top"
334 *             }
335 *         ],
336 *         "searchCount": 5,
337 *         "userpoint": 100,
338 *         "localizeDir": "en",
339 *         "selectOptions": {
340 *             "availability": {...},
341 *             "classification": {...}
342 *         },
343 *         "headtext": "Welcome to the waiting area",
344 *         "badges": [...],
345 *         "isLoggedIn": true,
346 *         "userData": {
347 *             "User": {
348 *                 "id": "123",
349 *                 "currency_code": "USD",
350 *                 "card_company": "Visa"
351 *             }
352 *         },
353 *         "userDataObj": {...},
354 *         "paymentPlanId": 1,
355 *         "userLang": 1,
356 *         "seriesSpecialArr": [...],
357 *         "seriesSelected": {...},
358 *         "counselor": {
359 *             "name": "John Doe",
360 *             "jp_name": "ジョン・ドウ",
361 *             "image_url": "http://example.com/image.jpg",
362 *             "country_name": "Japan"
363 *         },
364 *         "isHide": false,
365 *         "favId": [...],
366 *         "teacherFavs": [...],
367 *         "teacherFavsColors": [...],
368 *         "avatarActiveId": [...],
369 *         "teddyFav": true,
370 *         "occupationData": [...],
371 *         "counselorLampStatus": {...},
372 *         "hideCouselorFromMember": false,
373 *         "is_lite_plan_user": true,
374 *         "teacherList": [...],
375 *         "regions": [...],
376 *         "coinData": [...],
377 *         "searchData": {...},
378 *         "isLogin": true,
379 *         "savedConditionsCount": 5,
380 *         "preset": {...},
381 *         "searchCondition": {...},
382 *         "featureFilter": [...],
383 *         "user": {
384 *             "id": "123",
385 *             "name": "John Doe"
386 *         },
387 *         "disconnectionChatHash": "abc123",
388 *         "coins": [...],
389 *         "campaignTagSearch": {...}
390 *     }
391 *
392 * @apiError {String} status The status of the request (NG).
393 * @apiError {String} message The error message.
394 *
395 * @apiErrorExample {json} Error-Response:
396 *     {
397 *         "status": "NG",
398 *         "message": "Invalid request."
399 *     }
400 * 
401 * @apiSampleRequest off
402 */
403    public function index() {
404        // NJ-37582 redirect to appointment
405        $this->redirect('/appointment');
406        
407        $this->Teacher->hasAfterFind = true;
408        //mobile view only
409        
410        if ($this->RequestHandler->isMobile()) {
411            $this->layout = 'mobile';
412            $userpoints = $this->UsersPoint->getCurrentUserPoint($this->Auth->user('id'));
413
414            myTools::initializeApiTunnel(['SearchConditionsController']);
415
416            $displayRestrictionParams = array(
417                'lang' => $this->localizeDir
418            );
419
420            $searchConditions = new SearchConditionsController();
421            $params= array(
422                "users_api_token" => $this->Auth->user('api_token'),
423                "nc_terminal_type" => Configure::read('nc_terminal_type.pc'),
424                "displayRestrictionParams" => $displayRestrictionParams
425            );
426            $searchConditions->params = $params;
427
428            $search = json_decode($searchConditions->index(), true);
429            $savedSearchCount = count($search['conditions'] ?? []);
430
431            $this->set('searchCount', $savedSearchCount);
432            $this->set('userpoint', $userpoints);
433            $this->set('localizeDir',  $this->localizeDir);
434            return $this->render('/Mobile/Teacher/index');
435        }
436
437        $params = $this->params->query;
438        if (isset($params['stealth'])) {
439            TeacherTable::setStealthSettings($this->Cookie, $params['stealth']);
440        }
441        $selectOptions = array(
442            'availability' => TeacherTable::teacherAvailSelect2(),
443            //'nationality' => TeacherTable::teacherLocationSelect()
444            'classification' => TeacherTable::teacherClassificationSelect()
445        );
446        $this->set('selectOptions', $selectOptions);
447        $this->set('headtext', Configure::read('my.meta.waiting-index.headtext'));
448        $this->set('badges', TeacherBadgeTable::displayBadges());
449        $this->set('isLoggedIn', $this->Auth->loggedIn());
450        
451        $userData = $this->sharedUserData;//use shared user data 
452        // NJ-46: mypage banners
453        $userDataObj = new UserTable($userData['User']);
454        $paymentPlanId = $userDataObj->getMembershipTypeIndex();
455        $userLang = $this->CountryCode->getUserLanguageId($this->localizeDir);
456
457        // - conditions
458        $conditions = array(
459            'CampaignPcBanner.status' => 1,
460            'CampaignPcBannerCurrency.currency_code' => $userData['User']['currency_code'],
461            'CampaignPcBannerLanguage.language_id' => $userLang,
462        );
463
464        if ($userData['User']['card_company']) {
465            $conditions['CampaignPcBanner.payment_company LIKE'] = '%' . $userData['User']['card_company'] . '%';
466        }
467
468        if ($paymentPlanId) {
469            $conditions['FIND_IN_SET(?, CampaignPcBanner.user_status)'] = $paymentPlanId;
470        }
471        $this->log("[CampaignSettingsModal] conditions -> " .  json_encode($conditions), "debug");
472
473        $this->CampaignPcBanner->openDBReplica();
474        $allBanners = $this->CampaignPcBanner->find('all', array(
475            'fields' => array(
476                'CampaignPcBanner.id',
477                'CampaignPcBanner.campaign_url',
478                'CampaignPcBanner.start',
479                'CampaignPcBanner.end',
480                'CampaignPcBanner.image_url',
481                'CampaignPcBanner.event_tracking_tag',
482                'CampaignPcBanner.display_position'
483            ),
484            'conditions' => $conditions,
485            'joins' => array(
486                array(
487                    'table' => 'campaign_pc_banner_currencies',
488                    'alias' => 'CampaignPcBannerCurrency',
489                    'type' => 'LEFT',
490                    'conditions' => array('CampaignPcBannerCurrency.campaign_pc_banner_id = CampaignPcBanner.id')
491                ),
492                array(
493                    'table' => 'campaign_pc_banner_languages',
494                    'alias' => 'CampaignPcBannerLanguage',
495                    'type' => 'LEFT',
496                    'conditions' => array('CampaignPcBannerLanguage.campaign_pc_banner_id = CampaignPcBanner.id')
497                )
498            ),
499            'order' => 'CampaignPcBanner.priority_number ASC',
500            'recursive' => -1,
501        ));
502        $this->CampaignPcBanner->closeDBReplica();
503        $this->set('allBanners', $allBanners);
504
505        //instantiate view
506        $view = new View($this, false);
507        $view->layout = false;
508        //fetch data
509        $this->Teacher->hasAfterFind = true;
510        //NC-4548 from kids text description course
511        if (isset($_COOKIE['fromKidsDescription']) && $_COOKIE['fromKidsDescription'] !== 'null') {
512            $kidsCourseTeacher = array(
513                'sortRadio' => 'status',
514                'statusRadio' => 'all',
515                'teacherFeature' => array(0 => 'kids'),
516                'textbookRadioVal' => '2',
517                'courseOptionSearchCourseId' => '2',
518                'courseOptionChapterId' => '1',
519                'courseOptionLessonTextId' => '209',
520                'courseOptionConnectId' => '1',
521                'seriesOptionSearchTextBookCategoryId' => '11',
522                'badgeIds' => '11'
523            );
524
525            $this->Cookie->write('searchData', $kidsCourseTeacher);
526        }
527
528        //NJ-9440 - add status ALL + Live flg
529        if (isset($this->request->query['from_live_lesson_usage']) && $this->request->query['from_live_lesson_usage'] == 1) {
530            $liveTeachers = array(
531                'sortRadio' => 'status',
532                'statusRadio' => 'all',
533                'searchLiveLesson' => '1'
534            );
535            $this->Cookie->write('searchData', $liveTeachers);
536        }
537
538        if (!class_exists('myMemcached')) {
539            App::uses('myMemcached', 'Lib');
540        }
541        $memcache = new myMemcached();
542        if ($this->Auth->loggedIn()) {
543            $memKey = "searchCallanUsers_{$this->sharedUserData['User']['id']}";
544        } else {
545            $memKey = "searchCallanUsers";
546        }
547        if ($memSearchReserveData = $memcache->get($memKey)) {
548            $this->Cookie->write('searchData', $memSearchReserveData);
549            $memcache->delete($memKey);
550        }
551
552        // NJ-5836
553        $displayRestrictionParams = array(
554            'lang' => $this->localizeDir
555        );
556
557        // get display restriction setting
558        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
559
560        $query = array();
561        if ($this->isStudySapuriUser) {
562            // Get all Book
563            $getAllBookArr = array(
564                'user_id' => $this->Auth->user('id'),
565                'textbook_type' => 2,
566                'arrange_data' => 'trunk',
567                'preset' => 'off',
568                'user_locale' => $this->localizeDir,
569                'load_description' => false
570            );
571            $seriesCategoryData = $this->Textbook->getTextbooks($getAllBookArr);
572            $seriesArr = $seriesCategoryData['res_data'];
573
574            $getSeriesPresetArr = array(
575                'user_id' => $this->Auth->user('id'),
576                'textbook_type' => 2,
577                'select_method' => 'first',
578                'preset' => 'off',
579                'displayRestriction' => $displayRestriction
580            );
581            $seriesPresetData = $this->Textbook->getTextbooks($getSeriesPresetArr);
582            $seriesPreset = $seriesPresetData['res_data'];
583            $seriesId = $seriesPreset['TextbookCategory']['id'];
584            // NC-7228 set series id from saved search condition
585            $searchData = $this->Cookie->read('searchData');
586            if(isset($searchData['seriesOptionSearchTextBookCategoryId']) && !empty($searchData['seriesOptionSearchTextBookCategoryId'])){
587                $seriesId = $searchData['seriesOptionSearchTextBookCategoryId'];
588            }
589            $seriesSelected = isset($seriesArr[$seriesId]) ? $seriesArr[$seriesId] : 0;
590
591            if ($seriesSelected) {
592                $query['badgeIds'] = $seriesSelected;
593            }
594
595            $this->set('seriesSpecialArr', $seriesArr);
596            $this->set('seriesSelected', $seriesSelected);
597        }
598        // - NJ-6390
599        $searchParams = !empty($query) && $query? $query : $this->Cookie->read('searchData');
600        $highLightFlag = null;
601        if (isset($searchParams['keywordText']) && $searchParams['keywordText']) {
602            // - 1 = able to highlight the keyWord freeword search
603            $highLightFlag = 1;
604
605            // -delete session
606            $this->Session->delete('freeword-'.$this->Auth->user('id'));
607
608            // - add session for freewordArray
609            $this->Session->write('freeword-'.$this->Auth->user('id'), $this->request->data['keywordText']);
610        }
611
612        $data = [];
613
614        if (!$this->isStudySapuriUser) {
615            $counselor = $this->Teacher->find('first', array(
616                'fields' => array(
617                    'Teacher.name',
618                    'Teacher.jp_name',
619                    'Teacher.image_url',
620                    'CountryCode.country_name'
621                ),
622                'joins' => array(
623                    array(
624                        'type' => 'LEFT',
625                        'table' => 'country_codes',
626                        'alias' => 'CountryCode',
627                        'conditions' => 'Teacher.homeland2 = CountryCode.id'
628                    )
629                ),
630                'conditions' => array('Teacher.id' => Configure::read('default_counselor_detail')),
631                'recursive' => -1
632            ));
633        }
634
635        # check counselor if hidden
636        $where = array(
637            'user_id' => $this->Auth->user('id'),
638            'teacher_id' => Configure::read('default_counselor_detail')
639        );
640        $isHide = $this->BlockList->isTeacherHide($where);
641        $this->set('isHide', $isHide);
642
643        $favId = $this->Auth->loggedIn() ? $this->UsersFavorite->getTeacherIdList($this->Auth->user('id')) : array();
644//        NJ-10550
645        $teacherFavs = $this->Auth->loggedIn() ?
646            $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => array_values($favId)]) : [];
647        $colors = $this->UsersFavoriteCategoriesTeacher::COLORS;
648        $teacherFavsColors = []; //default
649
650        //-validate array variable
651        if (
652            $teacherFavs && 
653            is_array($teacherFavs)
654        ) {
655            $teacherFavsColors = array_map(function ($val) use ($colors) {
656                $index = array_search($val, array_column($colors, 'code'));
657                return $index >= 0 ? $colors[$index]['hex'] : '#F0295D';
658            }, $teacherFavs);
659        }
660
661        $this->set('teacherFavsColors', $teacherFavsColors);
662        // NC-7031 - avatar teachers
663        $avatarIdArr = array();
664        $teddyFav = false;
665        $getAvatarId = $this->Teacher->getParentAvatarTeacher();
666        if ($getAvatarId) {
667            $avatarIdArr = array_values($getAvatarId);
668
669            if ( $this->Auth->loggedIn() ) { // logged in
670                if ( $favId ) {
671                    // teddy
672                    $favAvaTParams = array(
673                        "avatar_id" => Configure::read('avatar_id.teddy'),
674                        "teacher_id" => $favId,
675                    );
676                    $checkTeddyFav = $this->Teacher->checkFavAvatarTeacher($favAvaTParams);
677
678                    if ($checkTeddyFav) {
679                        $teddyFav = true;
680                    }
681                }
682            }
683        }
684        //NC-9215 get teacher occupation industry and position
685        $this->set('occupationData', ClassRegistry::init('TeacherOccupationDetail')->getActiveOccupation());
686
687        // NJ-20272 : get counselor teacher lamp status
688        $counselorLampStatus = $this->Teacher->getCounselorLampStatus();
689
690        // NJ-9489 : check if membership is allowed to display counselor information
691         $_userData = $this->sharedUserData;
692        $hideCouselorFromMember = 0;
693        $n_isLitePlanUser = false;
694        if ($_userData) {
695            $_userPaymentPlan = $_userData['User']['payment_plan_id'];
696  
697            if (
698                  !$_userPaymentPlan ||
699                  in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
700            ) {
701                $hideCouselorFromMember = 1;
702            }
703
704            // NJ-37250 : set lite plan user flag 
705            if ($_userPaymentPlan && in_array($_userPaymentPlan, Configure::read('lite_payment_plans'))) {
706                $n_isLitePlanUser = true;
707            }
708        
709        }
710        $this->set('is_lite_plan_user',$n_isLitePlanUser);
711        $this->set('hideCouselorFromMember',$hideCouselorFromMember);
712
713        $view->set(array(
714            'teddyFav' => $teddyFav,
715            'avatarActiveId' => $avatarIdArr,
716            'counselor' => isset($counselor) ? $counselor : null,
717            'teachers' => isset($data['teacherData']) ? $data['teacherData'] : array(),
718            'counterData' => isset($data['limitGauge']) ? $data['limitGauge'] : 0,
719            'teacherRecordCount' => isset($data['teacherRecordCount']) ? $data['teacherRecordCount'] : 0,
720            'recordCount' => isset($data['teacherData']) ? count($data['teacherData']) : 0,
721            'limitRecord' => isset($data['limit']) ? $data['limit'] : 0,
722            'estimateRecord' => isset($data['limit']) && isset($data['teacherData']) ? count($data['teacherData']) * $data['limit'] : 0, 
723            'messageFlag' => false,
724            'isLoggedIn' => $this->Auth->loggedIn(),
725            'caller' => 'waiting',
726            'favId' => $favId,
727            'userId' => $this->Auth->loggedIn() ? $this->sharedUserData['User']['id'] : '',
728            'isHide' => $isHide,
729            'highLightFlag' => $highLightFlag,
730            'counselorLampStatus' => $counselorLampStatus
731        ));
732        $teacherList = $view->render('/MyPage/online_teachers');
733        $this->set('teacherList', $teacherList);
734
735
736        // NC-9142
737        $badges = $this->Textbook->getPresetTextbookSeriesId();
738
739        $userLangId = $this->CountryCode->getUserLanguageId(!empty($_userData['User']['native_language2']) ? $_userData['User']['native_language2'] : Configure::read('english_language'));
740
741        // - get regions list
742        $this->set('regions', $this->Teacher->getAvailableNationality($this->localizeDir, ($this->isStudySapuriUser ? true : false), ($this->isStudySapuriUser ? $badges : '')), array(), $userLangId); //nationalities of teachers
743        
744        $this->set('coinData', $this->TeacherRankCoin->getCoinAmount()); // set coin dropdown
745        $defaultSearchData = $this->Cookie->read('searchData');
746
747        if (isset($this->request->query['campaign_filter']) && $this->request->query['campaign_filter']) {
748            $campaignFilter = $this->request->query['campaign_filter'];
749            $defaultSearchData['statusRadio'] = 'all';
750            $defaultSearchData['textbookRadioVal'] = 2;
751            $this->Cookie->write('searchReserveData.seriesOptionSearchTextBookCategoryId', Configure::read('campaign_config.'.$campaignFilter.'.ENV.'.Configure::read('ENVIRONMENT').'.textbook_category_id'));
752        }
753        $this->set('searchData', $defaultSearchData);
754        $this->set('isLogin', $this->Auth->loggedIn());
755
756        // NC-7228 get stored search conditions
757        $savedConditionsCount = $this->UserSearchCondition->getSavedConditionsCount($this->sharedUserData['User']['id'], $n_isLitePlanUser);
758        $this->set('savedConditionsCount', $savedConditionsCount);
759
760        // set default preset params
761        $presetParams = array(
762            'user_id' => $this->Auth->user('id'),
763            'lang' => (isset($this->localizeDir) && $this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language'),
764            'is_pc_flg' => 1
765        );
766
767        //
768        if ((isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) && 
769            ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
770          ){
771            $presetParams['userValidForSSBEDT'] = true;
772        }
773
774        //
775        if (isset($this->sharedUserData['User'])) {
776            //
777            $userDataObj = new UserTable($this->sharedUserData['User']);
778
779            //
780            if (!empty($userDataObj->getMembershipTypeIndex())) {
781                $presetParams["userMembershipType"] = $userDataObj->getMembershipTypeIndex();
782            }
783
784            $presetParams['native_language2'] = $userDataObj->native_language2;
785
786        }
787
788        // get preset data
789        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
790
791        //
792        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
793            // for preset
794            $presetParams['connect_id'] = $preset_data['preset_connect_id'];
795            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
796
797        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
798            // use last viewed textbook if no preset data.
799            $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
800            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
801
802        }
803
804        // initial fetch preset 
805        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
806
807        // if no preset fetched - unsupported, fetch for tb with sort prioty 1
808        if(!$preset) {
809            unset($presetParams['connect_id']);
810            unset($presetParams['last_opened_date']);
811            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
812        }
813
814        $this->set('preset', $preset);
815        $this->set('searchCondition', $this->Session->read('savedSearchCondition'));
816        //- 
817        $this->set('featureFilter', $this->FeatureRatingItem->getFeatureFilters(['langId' => $this->CountryCode->getUserLanguageId($this->localizeDir)]));
818
819        // - NJ-11223 
820        $oUserData = new UserTable($this->sharedUserData['User']);
821        $this->set('user', $oUserData);
822        $this->Session->delete('savedSearchCondition');
823
824        // NJ-21309
825        $memcached = new myMemcached();
826        $disconnectionChatHash = $memcached->get('disconnectionChatHash');
827        $this->set('disconnectionChatHash', $disconnectionChatHash);
828
829
830        //- NJ-36852
831        $this->ReservationCoin->openDBReplica();
832        $coins = $this->ReservationCoin->find('all', ['conditions'=> array('status' => 1)]);
833        $this->ReservationCoin->closeDBReplica();
834
835          $coinArray = [];
836        if($coins && is_array($coins)) {
837            foreach ($coins as $c) {
838                $coinArray[] = $c['ReservationCoin']['coin'];
839            }
840        } 
841        
842        $this->set("coins", json_encode($coinArray));
843
844        # NJ-19429: Search Campaign Teachers
845        $campaignTagSearch = $this->CampaignTagControl->getCampaignTagStatusPC($this->sharedUserData['User']['id']);
846        $this->set('campaignTagSearch', $campaignTagSearch);
847        
848    }
849
850    private function checkProperProfile($teacherId) {
851        if (!is_numeric($teacherId)) {
852            $this->redirect('/waiting/detail/'.intval($teacherId), '301');
853        } else if (!ctype_digit($teacherId)){
854            $this->log("Invalid [teacher_id] ".$teacherId, "error");
855            throw new NotFoundException();
856        }
857
858        /* commented conflict to localization
859        if (isset($this->params->url) && $this->params->url != 'waiting/detail/'.$teacherId) {
860            $this->redirect('/waiting/detail/'.$teacherId, '301');
861        }*/
862    }
863
864    /**
865     * @api {get} /user/:language/waiting/detail/:teacherId/:highLightFlag detail()
866     * @apiName detail
867     * @apiGroup Waiting
868     * @apiDescription Retrieves the detailed information for a specific teacher in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
869     *
870     * @apiParam {String} language The language code.
871     * @apiParam {String} teacherId The ID of the teacher.
872     * @apiParam {String} [highLightFlag] The highlight flag.
873     * 
874     * @apiSuccess {Object} teacher The teacher object.
875     * @apiSuccess {String} teacher.id The ID of the teacher.
876     * @apiSuccess {String} teacher.name The name of the teacher.
877     * @apiSuccess {String} teacher.image The image URL of the teacher.
878     * @apiSuccess {Object} country The country object.
879     * @apiSuccess {String} country.name The name of the country.
880     * @apiSuccess {String} country.code The code of the country.
881     * @apiSuccess {Object} timezone The timezone object.
882     * @apiSuccess {String} timezone.name The name of the timezone.
883     * @apiSuccess {String} timezone.offset The offset of the timezone.
884     * @apiSuccess {Object} tutorCategory The tutor category object.
885     * @apiSuccess {String} tutorCategory.name The name of the tutor category.
886     * @apiSuccess {Number} timeDiff The time difference in seconds.
887     * @apiSuccess {Object} onair The on-air data.
888     * @apiSuccess {String} onair.id The ID of the on-air data.
889     * @apiSuccess {String} onair.status The status of the on-air data.
890     * @apiSuccess {String} userId The ID of the user.
891     * @apiSuccess {Object[]} series The list of textbook series.
892     * @apiSuccess {String} series.id The ID of the series.
893     * @apiSuccess {String} series.name The name of the series.
894     * @apiSuccess {Object[]} teacherTbRatings The teacher textbook ratings.
895     * @apiSuccess {String} teacherTbRatings.id The ID of the rating.
896     * @apiSuccess {String} teacherTbRatings.rating The rating value.
897     * @apiSuccess {Number} historyYear The number of years of teaching history.
898     * @apiSuccess {Number} historyMonth The number of months of teaching history.
899     * @apiSuccess {Object} teacherStatus1 The teacher status object.
900     * @apiSuccess {String} teacherStatus1.status The status of the teacher.
901     * @apiSuccess {Object} oOnair The on-air object.
902     * @apiSuccess {String} oOnair.id The ID of the on-air object.
903     * @apiSuccess {String} oOnair.status The status of the on-air object.
904     * @apiSuccess {Number} teacherTitleThreshold The teacher title threshold.
905     * @apiSuccess {Number} initialTeacherStatus The initial teacher status.
906     * @apiSuccess {Boolean} isFav Indicates if the teacher is favorited by the user.
907     * @apiSuccess {Boolean} isHide Indicates if the teacher is hidden by the user.
908     * @apiSuccess {Boolean} unsupportedBrowser Indicates if the browser is unsupported.
909     * @apiSuccess {Boolean} canReport Indicates if the user can report the teacher.
910     * @apiSuccess {Boolean} hideLimitedPlanReservation Indicates if the limited plan reservations should be hidden.
911     * @apiSuccess {Boolean} firstTimeLoggedIn Indicates if it is the user's first time logging in.
912     * @apiSuccess {Boolean} paidParent Indicates if the user is a paid parent.
913     * @apiSuccess {Number} velifyCount The count of phone verification logs.
914     * @apiSuccess {Object[]} countryCodes The list of country codes.
915     * @apiSuccess {String} countryCodes.code The code of the country.
916     * @apiSuccess {String} countryCodes.name The name of the country.
917     * @apiSuccess {Object} userCountry The user's country information.
918     * @apiSuccess {String} userCountry.name The name of the user's country.
919     * @apiSuccess {String} userCountry.code The code of the user's country.
920     * @apiSuccess {Boolean} deviceNotSupported Indicates if the device is not supported.
921     * @apiSuccess {Object} userLang The user's language information.
922     * @apiSuccess {String} userLang.name The name of the user's language.
923     * @apiSuccess {String} userLang.code The code of the user's language.
924     * @apiSuccess {Object} getCRData The country residence data.
925     * @apiSuccess {String} getCRData.country The country of residence.
926     * @apiSuccess {Object} residenceData The residence data.
927     * @apiSuccess {String} residenceData.city The city of residence.
928     * @apiSuccess {Boolean} residenceFlg Indicates if the residence flag is set.
929     * @apiSuccess {Boolean} login Indicates if the user is logged in.
930     * @apiSuccess {Object} preset The preset textbook information.
931     * @apiSuccess {String} preset.id The ID of the preset textbook.
932     * @apiSuccess {String} preset.name The name of the preset textbook.
933     * @apiSuccess {Boolean} presetIsLiveTextbook Indicates if the preset textbook is for live lessons.
934     * @apiSuccess {Object[]} apologyList The list of apologies.
935     * @apiSuccess {String} apologyList.id The ID of the apology.
936     * @apiSuccess {String} apologyList.message The message of the apology.
937     * @apiSuccess {Boolean} isNormalLitePlanUser Indicates if the user is on a normal lite plan.
938     * @apiSuccess {Object} getKeepMemo The keep memo information.
939     * @apiSuccess {String} getKeepMemo.id The ID of the keep memo.
940     * @apiSuccess {String} getKeepMemo.memo The memo text.
941     * @apiSuccess {String} textbookConnectId The textbook connect ID.
942     * @apiSuccess {Number} textbookCategoryTypeId The textbook category type ID.
943     * @apiSuccess {Boolean} highLightFlag Indicates if the highlight flag is set.
944     * @apiSuccess {Number} liveCoin The live lesson coin amount.
945     * @apiSuccess {Number} order The order of the teacher reviews.
946     * @apiSuccess {Object[]} lesson_history_data The lesson history data.
947     * @apiSuccess {String} lesson_history_data.id The ID of the lesson history.
948     * @apiSuccess {String} lesson_history_data.date The date of the lesson history.
949     * @apiSuccess {Boolean} showRating Indicates if the rating should be shown.
950     * @apiSuccess {Object} reserveAndCancel The reservation and cancellation data.
951     * @apiSuccess {Number} reserveAndCancel.reserved The number of reserved lessons.
952     * @apiSuccess {Number} reserveAndCancel.cancelled The number of cancelled lessons.
953     * @apiSuccess {Number} lessonHistoryCount The count of lesson history.
954     * @apiSuccess {Object} latestUserLesson The latest user lesson information.
955     * @apiSuccess {String} latestUserLesson.id The ID of the latest user lesson.
956     * @apiSuccess {String} latestUserLesson.date The date of the latest user lesson.
957     * @apiSuccess {Object} teacherRates The teacher rates.
958     * @apiSuccess {Number} teacherRates.rate The rate of the teacher.
959     * @apiSuccess {String} teacherIdCheck The teacher ID check.
960     * @apiSuccess {String} latestLessonData The latest lesson data.
961     * @apiSuccess {String} teacherLastLogin The last login time of the teacher.
962     * @apiSuccess {Number} teacherFavoriteCount The favorite count of the teacher.
963     * @apiSuccess {Object} teacherFeatures The teacher features.
964     * @apiSuccess {String} teacherFeatures.feature The feature of the teacher.
965     * @apiSuccess {Boolean} validCampaignDate Indicates if the campaign date is valid.
966     * @apiSuccess {Object} campaign The campaign information.
967     * @apiSuccess {String} campaign.id The ID of the campaign.
968     * @apiSuccess {String} campaign.name The name of the campaign.
969     * @apiSuccess {Object[]} ownReservationTeacherData The own reservation teacher data.
970     * @apiSuccess {String} ownReservationTeacherData.id The ID of the reservation.
971     * @apiSuccess {String} ownReservationTeacherData.date The date of the reservation.
972     * @apiSuccess {Number} studentDelayInSeconds The delay in seconds for the student lesson priority.
973     * @apiSuccess {Number} remainingSeconds The remaining seconds for the lesson.
974     * @apiSuccess {Boolean} ownReservationFlg Indicates if the user has their own reservation.
975     * @apiSuccess {String} teacherStatusColor The color of the teacher status.
976     * @apiSuccess {String} chatHash The chat hash.
977     * @apiSuccess {Boolean} liveLessonFlg Indicates if the lesson is a live lesson.
978     * @apiSuccess {Number} lessonRequestFlg The lesson request flag.
979     *
980     * @apiSuccessExample {json} Success-Response:
981     *     {
982     *         "teacher": {
983     *             "id": "123",
984     *             "name": "John Doe",
985     *             "image": "http://example.com/image.jpg"
986     *         },
987     *         "country": {
988     *             "name": "Japan",
989     *             "code": "JP"
990     *         },
991     *         "timezone": {
992     *             "name": "JST",
993     *             "offset": "+09:00"
994     *         },
995     *         "tutorCategory": {
996     *             "name": "English"
997     *         },
998     *         "timeDiff": 0,
999     *         "onair": {
1000     *             "id": "456",
1001     *             "status": "active"
1002     *         },
1003     *         "userId": "123",
1004     *         "series": [
1005     *             {
1006     *                 "id": "1",
1007     *                 "name": "Series 1"
1008     *             }
1009     *         ],
1010     *         "teacherTbRatings": [
1011     *             {
1012     *                 "id": "1",
1013     *                 "rating": "5"
1014     *             }
1015     *         ],
1016     *         "historyYear": 2,
1017     *         "historyMonth": 6,
1018     *         "teacherStatus1": {
1019     *             "status": "available"
1020     *         },
1021     *         "oOnair": {
1022     *             "id": "789",
1023     *             "status": "active"
1024     *         },
1025     *         "teacherTitleThreshold": 0,
1026     *         "initialTeacherStatus": 1,
1027     *         "isFav": true,
1028     *         "isHide": false,
1029     *         "unsupportedBrowser": false,
1030     *         "canReport": true,
1031     *         "hideLimitedPlanReservation": false,
1032     *         "firstTimeLoggedIn": false,
1033     *         "paidParent": false,
1034     *         "velifyCount": 1,
1035     *         "countryCodes": [
1036     *             {
1037     *                 "code": "JP",
1038     *                 "name": "Japan"
1039     *             }
1040     *         ],
1041     *         "userCountry": {
1042     *             "name": "Japan",
1043     *             "code": "JP"
1044     *         },
1045     *         "deviceNotSupported": false,
1046     *         "userLang": {
1047     *             "name": "Japanese",
1048     *             "code": "ja"
1049     *         },
1050     *         "getCRData": {
1051     *             "country": "Japan"
1052     *         },
1053     *         "residenceData": {
1054     *             "city": "Tokyo"
1055     *         },
1056     *         "residenceFlg": true,
1057     *         "login": true,
1058     *         "preset": {
1059     *             "id": "1",
1060     *             "name": "Preset Textbook"
1061     *         },
1062     *         "presetIsLiveTextbook": true,
1063     *         "apologyList": [],
1064     *         "isNormalLitePlanUser": true,
1065     *         "getKeepMemo": {
1066     *             "id": "1",
1067     *             "memo": "This is a memo."
1068     *         },
1069     *         "textbookConnectId": "123",
1070     *         "textbookCategoryTypeId": 1,
1071     *         "highLightFlag": true,
1072     *         "liveCoin": 100,
1073     *         "order": 0,
1074     *         "lesson_history_data": [
1075     *             {
1076     *                 "id": "1",
1077     *                 "date": "2023-12-01"
1078     *             }
1079     *         ],
1080     *         "showRating": true,
1081     *         "reserveAndCancel": {
1082     *             "reserved": 10,
1083     *             "cancelled": 2
1084     *         },
1085     *         "lessonHistoryCount": 10,
1086     *         "latestUserLesson": {
1087     *             "id": "1",
1088     *             "date": "2023-12-01"
1089     *         },
1090     *         "teacherRates": {
1091     *             "rate": 5
1092     *         },
1093     *         "teacherIdCheck": "123",
1094     *         "latestLessonData": "2023-12-01 (Fri)",
1095     *         "teacherLastLogin": "01/12/2023 (Fri)",
1096     *         "teacherFavoriteCount": 50,
1097     *         "teacherFeatures": {
1098     *             "feature": "Friendly"
1099     *         },
1100     *         "validCampaignDate": true,
1101     *         "campaign": {
1102     *             "id": "1",
1103     *             "name": "Campaign 1"
1104     *         },
1105     *         "ownReservationTeacherData": [
1106     *             {
1107     *                 "id": "1",
1108     *                 "date": "2023-12-01"
1109     *             }
1110     *         ],
1111     *         "studentDelayInSeconds": 0,
1112     *         "remainingSeconds": 0,
1113     *         "ownReservationFlg": true,
1114     *         "teacherStatusColor": "green",
1115     *         "chatHash": "abc123",
1116     *         "liveLessonFlg": true,
1117     *         "lessonRequestFlg": 1
1118     *     }
1119     *
1120     * @apiError {String} status The status of the request (NG).
1121     * @apiError {String} message The error message.
1122     *
1123     * @apiErrorExample {json} Error-Response:
1124     *     {
1125     *         "status": "NG",
1126     *         "message": "Invalid request."
1127     *     }
1128     * 
1129     * @apiSampleRequest off
1130     */
1131    public function detail($teacherId = null, $highLightFlag = null) {
1132
1133        if (is_null($teacherId)) {
1134            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
1135        }
1136
1137        if (isset($this->request->query['emergency']) && !$this->isStudySapuriTosUser) {
1138            return $this->redirect(myTools::getUrl() . '/waiting');
1139        }
1140
1141        //set mobile view
1142        if (myTools::defaultAction($this) || (isset($_GET['classViewTeacher']) && $_GET['classViewTeacher'] == 1)) {
1143            return $this->spDetail($teacherId);
1144        }
1145        $counselorParams = array(
1146            'type' => 'count',
1147            'args' => array(
1148                'conditions' => array(
1149                    'id' => $teacherId,
1150                    'counseling_flg' => 1
1151                ),
1152                'recursive' => -1
1153            )
1154        );
1155
1156        // - NC-3802: redirect to mypage if counselor teacher
1157        if ($this->Teacher->getTeachers($counselorParams)) {
1158            return $this->redirect('/mypage');
1159        }
1160
1161        $customer_support_flg = $this->TeacherDetail->isCustomerSupportTeacher($teacherId);
1162        //NJ-36255 - redirect to  customer support page if customer support teacher
1163        if($customer_support_flg){
1164            return $this->redirect('/customersupport_detail');
1165        }
1166        
1167        //NJ-65055: params for checking teacher is hidden
1168        $isTeacherHiddenParams = array(
1169            'user_id' => $this->Auth->user('id'),
1170            'teacher_id' => $teacherId
1171        );
1172
1173        if ((BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) || $this->BlockList->isTeacherHide($isTeacherHiddenParams)) {
1174            return $this->redirect('/waiting');
1175        }
1176
1177        // - NC-7031: redirect avatar
1178        $avatarData = $this->isAvatar($teacherId);
1179        if ($avatarData) {
1180            $getAId = $avatarData;
1181            return $this->redirect('/avatar_detail/'.$getAId);
1182        }
1183
1184        //redirect to proper profile
1185        $this->checkProperProfile($teacherId);
1186
1187        $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
1188        $queryCondition = array(
1189            'fields' => array(
1190                    'TeacherRankCoin.coins',
1191                    'TeacherRankCoin.reserve_coin_settings_flg',
1192                    'LessonOnair.id',
1193                    'LessonOnair.teacher_id',
1194                    'LessonOnair.user_id',
1195                    'TeacherRankCoin.limited_plan_reservation'
1196                ),
1197            'joins' => array(
1198                array(
1199                    'type' => 'LEFT',
1200                    'table' => 'teacher_rank_coins',
1201                    'alias' => 'TeacherRankCoin',
1202                    'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
1203                )
1204            ),
1205            'conditions' => array(
1206                array('Teacher.id' => $teacherId)
1207            ),
1208            'show' => 'first'
1209        );
1210
1211        $commonTeacherStatusParams = array(
1212            'page_display' => 'listTeacher',
1213            'query_conditions' => $queryCondition
1214        );
1215        $data = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
1216
1217        if (!$data) {
1218            return $this->redirect('/waiting/');
1219        }
1220
1221        if (in_array($data['Teacher']['rank_coin_id'], $this->blockMemberSettings)) {
1222            return $this->redirect('/mypage');
1223        }
1224        // NJ-51 : Set delay for student lesson priority group
1225        $studentDelayInSeconds = 0;
1226        $standbyStatus = false;
1227        $remainingSeconds = 0;
1228        $chatHash = $this->request->query('chatHash') ?? null;
1229
1230        if( isset($data['LessonOnair']) && $data['LessonOnair'] ) {
1231            $loAir = $data['LessonOnair'];
1232            if( (isset($loAir['status']) && $loAir['status'] == 1) ) {
1233                $standbyStatus = true;
1234            }
1235        }
1236
1237        if( isset($data['TeacherStatus']) && $data['TeacherStatus'] && $data['TeacherStatus']['teacher_status'] == 2 ) {
1238            $tstatus = $data['TeacherStatus'];
1239            if( isset($tstatus['created']) && $tstatus['created'] ) {
1240                if( isset($data[0]['teacher_status_standby_duration']) && $data[0]['teacher_status_standby_duration'] ) {
1241                    if( (int)$data[0]['teacher_status_standby_duration'] <= (int)$this->studentLessonPriorityTimeDelayInSeconds ) {
1242                        $remainingSeconds = (int)$this->studentLessonPriorityTimeDelayInSeconds - (int)$data[0]['teacher_status_standby_duration'];
1243                    }
1244                }
1245                $studentDelayInSeconds = (int) $remainingSeconds * 1000;
1246            }
1247        }
1248
1249        //- check lesson type
1250        $liveLessonFlg = isset($data['LessonOnair']['live_lesson_flg']) ? $data['LessonOnair']['live_lesson_flg'] : 0;
1251
1252        //-get userid
1253        $userId = isset($this->sharedUserData['User']['id']) ? $this->sharedUserData['User']['id'] : $this->Auth->user('id');
1254
1255        $ownReservationFlg = 0;
1256        if ( $userId ) {
1257            $teacherStatusColor = '';
1258            $teacherObj = new TeacherTable($data['Teacher']);
1259            $tsObj = new TeacherStatusTable($data['TeacherStatus']);
1260
1261            // get reservation
1262            $nextReservation = LessonScheduleTable::getReservation(array(
1263                'LessonSchedule.teacher_id' => $teacherObj->id,
1264                'LessonSchedule.user_id' => $userId
1265            ));
1266        
1267
1268            //-- if user cannot use live lesson -> force to disabled live lesson flag
1269            if ( isset($data['LessonOnair']['live_lesson_flg']) && empty($allowLiveLesson) ) {
1270                $data['LessonOnair']['live_lesson_flg'] = 0;
1271            }
1272
1273            $loStatusParams = array(
1274                'LessonOnair' => $data['LessonOnair'],
1275                'Teacher' => $data['Teacher'],
1276                'TeacherStatus' => $tsObj,
1277                'nextReservation' => isset($nextReservation['teacher_id']) ? $nextReservation['teacher_id'] : null,
1278                'userId' => $userId
1279            );
1280            $teacherStatus = LessonOnairTable::teacherStatusColor($loStatusParams);
1281            $teacherStatusColor = TeacherTable::teacherStatusCSS($teacherStatus);
1282            if( $teacherStatus == '5' ) {
1283                $ownReservationFlg = 1;
1284            }
1285
1286            // - user callan unli option flg
1287            $callan_option = isset($this->sharedUserData['User']['callan_option']) ? $this->sharedUserData['User']['callan_option'] : 0;
1288
1289            // - user native unli option flg
1290            $native_option = isset($this->sharedUserData['User']['native_option']) ? $this->sharedUserData['User']['native_option'] : 0;
1291
1292            $can_use_callan_option = 0;
1293            if($callan_option || $native_option) {
1294                $can_use_callan_option = 1;
1295            }
1296
1297            $this->set('can_use_callan_option', $can_use_callan_option);
1298
1299            // - teacher callan unli option flg
1300            $unlimited_option_flag = $this->HomeBasedRankBasicAmount->getUnlimitedOptionFlg($teacherObj->current_rank_id);
1301            $callan_option_teacher_flg = (isset($unlimited_option_flag['callan_unlimited_option_flg']) && $unlimited_option_flag['callan_unlimited_option_flg']) ? $unlimited_option_flag['callan_unlimited_option_flg'] : 0; 
1302            $this->set('callan_option_teacher_flg', $callan_option_teacher_flg);
1303            
1304            // - check if has callan badge
1305            $teacher_callan_badge = ClassRegistry::init('TeacherBadge')->checkCallanBadges(array('teacher_id' => $teacherId));
1306            $this->set('teacher_callan_badge', $teacher_callan_badge);
1307        }
1308
1309        //-default
1310        $liveStatus = 0;
1311
1312        //- fetch live waiting reservation
1313        $waitingReservationLive = [];
1314        if ($this->Auth->loggedIn() && $liveLessonFlg) {
1315            //- fetch user reservation
1316            $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($userId);
1317
1318            if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
1319                $liveStatus = 0;
1320            } else {
1321                //- if lesson started
1322                if (
1323                    !is_null($data['LessonOnair']['connect_id']) &&
1324                    !is_null($data['LessonOnair']['user_id'])
1325                ) {
1326                    if ($data['LessonOnair']['user_id'] == $userId) {
1327                        $liveStatus = 4;
1328                    } else {
1329                        //- check live status
1330                        $liveStatus = $this->LessonOnairsViewer->onGoingLiveStatus([
1331                            'user_id' => $userId,
1332                            'chat_hash' => $data['LessonOnair']['chat_hash']
1333                        ]);
1334
1335                        //-- override status to watch
1336                        if ($liveStatus == 1) {
1337                            $liveStatus = 2; //view live
1338                        }
1339                    }
1340                } else {
1341                    $waitingReservationLive = $this->LessonSchedule->getWaitingLiveReservation([
1342                        'teacher_id' => $teacherId
1343                    ]);
1344
1345                    //-has reservation
1346                    if ($waitingReservationLive) {
1347                        if ($waitingReservationLive['LessonSchedule']['user_id'] == $userId) {
1348                            $liveStatus = (date('i') >= 0 && date('i') <= 26) || (date('i') >= 30 && date('i') <= 56) ? 4 : 0;
1349                        } else {
1350                            $liveStatus = 1; //live will start
1351                        }
1352                    }
1353                }
1354            }
1355        }        
1356
1357        //redirect if withdrawn teacher
1358        if ($data['Teacher']['status'] <> 1 || $data['Teacher']['inactive_flg'] == 1) {
1359            if ($this->Auth->loggedIn()) {
1360                return $this->redirect(myTools::geturl() . '/mypage');
1361            } else {
1362                return $this->redirect(myTools::geturl() . '/waiting');
1363            }
1364        }
1365
1366        if (isset($data['LessonOnair'])) {
1367            $tmp = (object) $data['LessonOnair'];
1368            if (!$tmp->id) {
1369                $data['LessonOnair'] = null;
1370            }
1371        }
1372
1373        // get teacher information
1374        $teacher = new TeacherTable($data['Teacher']);
1375        $country = new TeacherTable($data['CountryCode']);
1376        $timezone = new TimezoneTable($data['Timezone']);
1377        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
1378
1379        $timeDiff = 0;
1380        if (isset($timezone->continent_id) && isset($timezone->city_eng)) {
1381            $timeDiffData = $this->Timezone->computeTimeDiff(array(
1382                'continent_id' => $timezone->continent_id,
1383                'city' => $timezone->city_eng
1384            ));
1385
1386            //
1387            if ($timeDiffData['success']) {
1388                $timeDiff = $timeDiffData['timeDiff'];
1389            }
1390        }
1391
1392        $onair = $data['LessonOnair'];
1393        $onairDataArr = isset($data['LessonOnair']) && $data['LessonOnair'] ? $data['LessonOnair'] : array();
1394
1395        $userId = ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null;
1396
1397        $fieldArr = array(
1398            'TextbookCategory.name',
1399            'TextbookCategory.id',
1400            'TextbookCategory.type_id',
1401            'TeacherBadge.textbook_category_id',
1402            'TeacherBadge.badge_flg',
1403            'TextbookCategory.type_id',
1404            'TextbookCategory.image_big_url'
1405        );
1406        $joinArr = array(
1407            array(
1408                'table' => 'teacher_badges',
1409                'alias' => 'TeacherBadge',
1410                'type' => 'LEFT',
1411                'conditions' => array('TeacherBadge.textbook_category_id = TextbookCategory.id', 'TeacherBadge.teacher_id' => $teacherId)
1412            )
1413        );
1414
1415        // if the user's language is zh-tw, display chinese textbook badge name
1416        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
1417            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
1418            if($langId){
1419                $joinArr[] = array(
1420                    'type' => 'LEFT',
1421                    'table' => 'global_textbook_categories',
1422                    'alias' => 'GlobalTextbookCategory',
1423                    'conditions' => array(
1424                        'GlobalTextbookCategory.language_id' => $langId,
1425                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
1426                    )
1427                );
1428                $this->TextbookCategory->virtualFields = array(
1429                    'gl_name' => 'GlobalTextbookCategory.gl_name'
1430                );
1431                $fieldArr[] = 'gl_name';
1432            }
1433        }
1434
1435        $conArr = array(
1436            'TextbookCategory.status' => 1,
1437            'TextbookCategory.type_id' => 2
1438        );
1439
1440        # get studydapuri textbooks
1441        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
1442        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
1443            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
1444            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
1445        } elseif ($this->isStudySapuriTosUser) {
1446            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
1447        } else {
1448            $exCat = Configure::read('all_sapuri_textbook_category_types');
1449            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
1450        }
1451
1452        //NJ-24096: get last reservation textbook type
1453        $reservationTextbookConnectId = "";
1454        if ($userId) {
1455            $sapuriFlg = ($this->isStudySapuriTosUser || $this->isStudySapuriUser) ? true : false;
1456            $lastReservationData = LessonScheduleTable::getLastReservation($this->Auth->user('id'), $sapuriFlg);
1457
1458            if (!empty($lastReservationData['LessonSchedule']['connect_id'])) {
1459                $reservationTextbookConnectId = $lastReservationData['LessonSchedule']['connect_id'];
1460            } else {
1461                $this->User->openDBReplica();
1462                $checkUserFirstFlg = $this->LessonSchedule->field('connect_id', array('user_id' => $userId));
1463                $this->User->closeDBReplica();
1464                if (empty($checkUserFirstFlg)) {
1465                    $defaultParams = array(
1466                        'user_id' => $userId,
1467                        'lang' => $userData->native_language2 ?? $this->localizeDir,
1468                    );
1469                    $defaultReservation = $this->Textbook->getDefaultReservationTBConnectId($defaultParams);
1470                    if ($defaultReservation) {
1471                        $reservationTextbookConnectId = $defaultReservation;
1472                    }
1473                }
1474            }
1475        }
1476        $this->set(compact('reservationTextbookConnectId'));
1477
1478        // NJ-5836
1479        $displayRestrictionParams = array(
1480            'lang' => $this->localizeDir
1481        );
1482
1483        // get display restriction setting
1484        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
1485
1486        // NJ-5836 add condition for display restriction
1487        if(isset($displayRestriction['field']) && $displayRestriction['field']){
1488            // set condition for display restriction
1489            $conArr['TextbookCategory.'.$displayRestriction['field']] = 1;
1490        }
1491
1492        //get series and badge
1493        $series = $this->TextbookCategory->find('all', array(
1494            'fields' => $fieldArr,
1495            'conditions' => $conArr,
1496            'joins' => $joinArr,
1497            'order' => array(
1498                'TextbookCategory.sort' => 'ASC'
1499            )
1500        ));
1501
1502        $this->set('series', $series);
1503        myTools::initializeApiTunnel(array('TeachersDetailController'));
1504        $teachersDetail = new TeachersDetailController();
1505
1506        $teacherTbRatings = array();
1507        
1508        if (isset($series) && is_array($series) && count($series) > 0) {
1509            foreach($series as $books){            
1510                $categoryId = $books['TextbookCategory']['id'];
1511                $params = array(
1512                    'teacher_id' =>  (int) $teacherId,
1513                    'textbook_category_id' => (int) $categoryId,
1514                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
1515                );
1516                $teachersDetail->params = $params;        
1517                $decodeResp = json_decode($teachersDetail->teacherTextbookRating());
1518                $teacherTbRatings[$categoryId] = $decodeResp->teacher_textbook_rating;
1519            }
1520        }
1521
1522        $this->set('teacherTbRatings', $teacherTbRatings);
1523
1524        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
1525
1526        $this->set('historyMonth',$historyMonth);
1527        $this->set('historyYear',$historyYear);
1528
1529        //teacher_status if login or break
1530        $teacherStatus1 = $this->TeacherStatus->find('first', array(
1531            'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1', 'TeacherStatus.remarks2'),
1532            'conditions' => array('TeacherStatus.teacher_id' => $teacher->getId())
1533        ));
1534
1535        //lesson onair
1536        if (!empty($onair)) {
1537            $oOnair = new LessonOnairTable($onair);
1538        } else {
1539
1540            if (!empty($teacherStatus1)) {
1541                $oOnair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
1542            } else {
1543                $oOnair = 0;
1544            }
1545        }
1546
1547        // NJ-17264
1548        $teacherTitleThreshold = 0;
1549        if(isset($data['TitleThresholdTeacher']['title_type'])){
1550            $teacherTitleThreshold = $data['TitleThresholdTeacher']['title_type'];
1551        }
1552
1553        // inital teacher status
1554        $initialTeacherStatus = isset($teacherStatus1['TeacherStatus']) && $teacherStatus1['TeacherStatus']['status'] ? $teacherStatus1['TeacherStatus']['status'] : 0;
1555
1556        //favorite
1557        $where = array(
1558            'UsersFavorite.user_id'     => $this->Auth->user('id'),
1559            'UsersFavorite.teacher_id'     => $teacherId,
1560        );
1561        $isFav = $this->UsersFavorite->find('count', array('conditions' => $where));
1562
1563        // NC-5897 : check if teacher was hide by user.
1564        $where = array(
1565            'user_id' => $this->Auth->user('id'),
1566            'teacher_id' => $teacherId,
1567        );
1568        $isHide = $this->BlockList->isTeacherHide($where);
1569        $this->User->recursive = -1;
1570        $data = $this->User->findById($userId);
1571        $user = isset($data['User'])?$data['User']: null;
1572        $unsupportedBrowser = false;
1573        $browser =  $this->request->header('User-Agent');
1574
1575        if (preg_match('/(Edg|Edge)/i',$browser) ) {
1576            $unsupportedBrowser = false;
1577        } elseif (!preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
1578            $unsupportedBrowser = true;
1579        }
1580        $canReport = true;
1581        if ($user) {
1582            $userData = new UserTable($data['User']);
1583            $userMembership = $userData->getUserMembership();
1584            $this->set('user_lang', $userData->native_language2);
1585            // if weekly plan user
1586            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($userData->payment_plan_id);
1587            $corporateUser = isset($corporateType) ? $corporateType : '';
1588
1589            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
1590            $canReport = $userData->getMembershipTypeIndex();
1591            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
1592        }
1593        $this->set('unsupportedBrowser', $unsupportedBrowser);
1594        // NC-6615 check if user can report the teacher
1595        $this->set('canReport', $canReport);
1596
1597        $hideLimitedPlanReservation = false;
1598        if ($tutorCategory->limited_plan_reservation == 0 && (isset($corporateUser) && $corporateUser ==  Configure::read('corporate_type.limited'))) {
1599            $hideLimitedPlanReservation = true;
1600        }
1601
1602        $firstTimeLoggedIn = false;
1603        if (empty($user['last_login_time'])) {
1604            $firstTimeLoggedIn = true;
1605        }
1606
1607        $paidParent = false;
1608
1609        $velifyCount = $this->PhoneVerifyCheckLog->find('count',array(
1610            'conditions' => array(
1611                'user_id' => $this->Auth->user('id'),
1612                'status' => 0
1613            )
1614        ));
1615
1616        $countryCodes = $this->CountryCode->find('all',array(
1617            'fields' => array(
1618                'code',
1619                'country_name'
1620            ),
1621            'order' => 'country_name ASC'
1622        ));
1623        $this->set('countryCodes',$countryCodes);
1624
1625        $userCountry['CountryCode']['country_name'] = '';
1626        $userCountry['CountryCode']['code'] = '';
1627        if(!empty($data['User']['country_code'])){
1628            $userCountry = $this->CountryCode->find('first',array(
1629                'conditions' => array(
1630                    'code' => $data['User']['country_code']),
1631                'fields' => array(
1632                    'code',
1633                    'country_name')
1634            ));
1635            if(empty($userCountry)){
1636                $userCountry['CountryCode']['code'] = '';
1637            }
1638        }
1639        $this->set('countryCodes',$countryCodes);
1640
1641        //check if user is child by checking its parent id not empty
1642        if (isset($data['User']['parent_id'])) {
1643            $paidParent = $this->User->checkPaidParent($data['User']['parent_id']);
1644        }
1645        #$lesson_count=0;
1646        // 管理者権限会員は無制限でレッスン出来る
1647        if (isset($user['admin_flg']) && $user['admin_flg']=='1') {
1648            $user['charge_flg'] = 1;
1649            $lesson_count=0;
1650            $lesson_count_today = 0;
1651        }
1652
1653        if (empty($user['enquate6'])) {
1654            $user['enquate6'] = '1';
1655        }
1656
1657        if (empty($user['enquate7'])) {
1658            $user['enquate7'] = '1';
1659        }
1660
1661        // if tos user
1662        if (isset($this->sharedUserData['UsersExtend']['id'])) {
1663            $user['tos_user'] = true;
1664        }
1665
1666        //number of stusap lesson
1667        $stusapLessonCount = (int)$teacher->stusap_lesson_count + (int)$teacher->stasapu_tos_lesson_count;
1668        //number of lesson
1669        $lessonCount = (int)$teacher->lesson_count;
1670
1671        // - prepare head text
1672        $headTextWD = $pageTitleWD = $teacher->name;
1673        $metaDescWD = "";
1674        if ($this->localizeDir == Configure::read('default.user_language')) {
1675            $headTextWD .= '('.$teacher->jp_name.')';
1676            $pageTitleWD .=  '('.$teacher->jp_name.')';
1677            //$metaDescWD .= '('.$teacher->jp_name.')';
1678        }
1679
1680        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { // if the language is Custom language format
1681            $headTextWD .= '&ensp;'. __d('waiting','レッスン数').': '.$lessonCount . ' ' . lcfirst(($lessonCount <= 1 ?  __dx('waiting', 'singular', '回') :  __d('waiting', '回'))); 
1682        } else { // if the language is not Custom language format
1683            $headTextWD .= '&ensp;'. __d('waiting','レッスン数').':'.$lessonCount. __d('waiting','回');
1684        }
1685        $pageTitleWD .= '&ensp;' . sprintf(__d('waiting', 'レッスン:%s回 - 講師詳細 | オンライン英会話のネイティブキャンプ'), $lessonCount);
1686        //$metaDescWD .= __d('waiting','講師の紹介ページです。').$teacher->getMetaDescription();
1687
1688        //prepare meta image 
1689        $_teacherImgUrl = $teacher->getImageUrl();
1690
1691        //check if teacher has no image 
1692        if (empty($teacher->image_url) || !$teacher->image_url) {
1693            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
1694            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
1695        }
1696
1697
1698        // - set page meta information
1699        $this->set('headtext', $headTextWD);
1700        $this->set('title_for_layout', $pageTitleWD);
1701        // $this->set('meta_description', $metaDescWD);
1702        $this->set('meta_keywords',$teacher->name.',講師,オンライン英会話,ネイティブキャンプ');
1703        $this->set('counselingFlg',$teacher->counseling_flg);
1704        $this->set('meta_teacher_img',$_teacherImgUrl);
1705
1706        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
1707        $options['language_id'] = $reviewLanguage[0] ?? null;
1708        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
1709
1710        $userTable = new UserTable($this->Auth->user());
1711        $sapuriPlan = $userTable->isStudySapuri();
1712        $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
1713        if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
1714            $options['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
1715        } else {
1716            $options['textbook_category_type_not_in'] = $sapuriTextbookType;
1717        }
1718        $commentCount = $this->UsersClassEvaluation->getCommentCount($teacherId , $options);
1719        $approveFlag = $this->UsersClassEvaluation->getApproveEvalCount($teacherId);
1720
1721        $get_weekly_rating = $this->UsersClassEvaluation->getRatings($teacherId,true);
1722        $get_weekly_rating['TeacherWeeklyRating']['averageRate'] ??= '';
1723        if ($get_weekly_rating['TeacherWeeklyRating']['averageRate']) {
1724            if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) {
1725                $get_weekly_rating['TeacherWeeklyRating']['ratings'] = number_format($get_weekly_rating['TeacherWeeklyRating']['averageRate'], 2, ',', '');
1726            } else {
1727                $get_weekly_rating['TeacherWeeklyRating']['ratings'] = $get_weekly_rating['TeacherWeeklyRating']['averageRate'];
1728            }
1729        }
1730
1731        /* -- NC-5293 start -- */
1732        $this->loadModel('Translation');
1733        $translationCategories = Configure::read('translation_categories');
1734        $translateParams = array(
1735            'languageCode' => $this->lang_iso,
1736            'categoryId' => $translationCategories['teacher_message'],
1737            'messageId' => $teacher->id,
1738            'text' => $teacher->message
1739        );
1740
1741        $translatedMessageParams = $translateParams;
1742        $translateParams['categoryId'] = $translationCategories['teacher_self_introduction_third_pp'];
1743        $translateParams['text'] = $teacher->self_introduction_third_pp;
1744        $translatedSelfIntroductionThirdPpParams = $translateParams;
1745        /* -- NC-5293 end -- */
1746
1747        // Translate and save translated data
1748        $globalTranslate = TeacherTable::translate(array(
1749            'id' => $teacherId,
1750            'lang'=> isset($this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language'),
1751            'controller' => static::class
1752        ));
1753        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
1754        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
1755        $this->set('message', $translatedMessageTranslation);
1756        $this->set('intro', $translatedThirdppTranslation);
1757
1758        //find the selfintro 
1759        $TeacherTable = new TeacherTable($teacher);
1760        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
1761        $_userSelfIntro = strip_tags($_userSelfIntro); 
1762
1763        //set the new meta description
1764        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
1765        $this->set('meta_description', $metaDescWD);
1766
1767        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($data['User']['payment_plan_id']);
1768        $canCoinPurchase = true;
1769        if (isset($data['User']['corporate_id']) && isset($corporateType)) {
1770            if (in_array($corporateType, array(Configure::read('corporate_type.standard'), Configure::read('corporate_type.premium')))) {
1771                $canCoinPurchase = true;
1772            } else {
1773                $canCoinPurchase = false;
1774            }
1775        }
1776
1777        //
1778        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacher->id);
1779
1780        # Get teachers reservation amounts. | NJ-2038, for hb teachers only not applicable for counselor/avatar
1781        $coinParams =  array(
1782            'current_rank_id' => $teacherCurrentRankId,
1783            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
1784            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
1785            'student_native_option' => $userData->native_option,
1786            'home_flg' => $teacher->home_flg,
1787            'counseling_flg' => $teacher->counseling_flg,
1788            'avatar_parent_flg' => $teacher->avatar_parent_flg,
1789            'avatar_flg' => $teacher->avatar_flg,
1790            'native_speaker_flg' => $teacher->native_speaker_flg
1791        );
1792
1793        // get teacher coin settings
1794        $teacherCoinData = $this->Teacher->getTeacherReserveCoin($coinParams);
1795
1796        $teacherCoinWithOp = $teacherCoinBeforeDiscount = null;
1797        $displayNativeOptionAmountFlg = false;
1798        if($teacherCoinData){
1799            // set teacher reservation coin
1800            $teacherCoin = (isset($teacherCoinData['reserve_coin']) && is_numeric($teacherCoinData['reserve_coin'])) ? $teacherCoinData['reserve_coin'] : 0;
1801            $teacherCoinBeforeDiscount = $teacherCoinData['reserve_coin_before_discount'];
1802            $teacherCoinWithOp = $teacherCoinData['reserve_coin_with_op'];
1803            $displayNativeOptionAmountFlg = $teacherCoinData['display_native_option_amount_flg'];
1804        }
1805        $teacherCoin = $teacherCoin ?? 0;
1806        $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoin / 2 : $teacherCoin;
1807
1808        $teacherCallanDiscount = $teacher->getCallanHalfPrice();
1809
1810        $sapuriCoin = 0;
1811        if ($this->isStudySapuriUser) {
1812            $teacherParams = array(
1813                'teacher_id' => $teacher->id,
1814                'current_rank_id' => $teacherCurrentRankId
1815            );
1816            $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
1817        }
1818
1819        $ongoingLessonWithOtherStudentButtonDelay = 0;
1820        if($onairDataArr){
1821            if( 
1822                (isset($onairDataArr['user_id']) && $onairDataArr['user_id'] != $userId) && 
1823                (isset($onairDataArr['status']) && $onairDataArr['status'] == '3') && 
1824                (int)$this->studentLessonPriorityTimeDelayInSeconds > 0
1825            ) {
1826                $ongoingLessonWithOtherStudentButtonDelay = 1;
1827            }    
1828        }
1829    
1830        // set lesson review modal on/off
1831        $this->set('lesson_review_flg', $data['User']['lesson_review_flg']);
1832        $where = array(
1833            'UsersFavorite.teacher_id' => $teacherId,
1834        );
1835
1836        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => $where));
1837        $teacherFavColor = $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => $isFav? [$teacher->id]: []]);
1838        $teacherFavsColors = $this->UsersFavoriteCategoriesTeacher->parseToHexColor([
1839            'favIds' => $isFav? [$teacher->id]: [],
1840            'favIdsTeacherCategory' => $teacherFavColor
1841        ]);
1842        
1843        // NJ-3696
1844        $this->LessonOnairsLog->openDBReplica();
1845        $textbook = $this->LessonOnairsLog->find('first', array(
1846            'fields' => array(
1847                'TextbookCategories.id',
1848                'TextbookCategories.textbook_category_type'
1849            ),
1850            'joins' => [
1851            [
1852                'table' => 'textbook_connects',
1853                'alias' => 'TextbookConnects',
1854                'type' => 'left',
1855                'conditions' => ["TextbookConnects.id = LessonOnairsLog.connect_id"]
1856            ],
1857            [
1858                'table' => 'textbook_categories',
1859                'alias' => 'TextbookCategories',
1860                'type' => 'left',
1861                'conditions' => ['TextbookCategories.id = TextbookConnects.category_id']
1862            ]
1863        ],
1864            'conditions' => array('LessonOnairsLog.chat_hash' => $chatHash),
1865            'recursive' => -1
1866        ));
1867        $this->LessonOnairsLog->closeDBReplica();
1868    
1869        if(!$textbook){
1870            $this->LessonOnair->openDBReplica();
1871            $textbook = $this->LessonOnair->find('first', array(
1872                'fields' => array(
1873                    'TextbookCategories.id',
1874                    'TextbookCategories.textbook_category_type'
1875                ),
1876                'joins' => [
1877                    [
1878                        'table' => 'textbook_connects',
1879                        'alias' => 'TextbookConnects',
1880                        'type' => 'left',
1881                        'conditions' => ["TextbookConnects.id = LessonOnair.connect_id"]
1882                    ],
1883                    [
1884                        'table' => 'textbook_categories',
1885                        'alias' => 'TextbookCategories',
1886                        'type' => 'left',
1887                        'conditions' => ['TextbookCategories.id = TextbookConnects.category_id']
1888                    ]
1889                ],
1890                'conditions' => array('LessonOnair.chat_hash' => $chatHash),
1891                'recursive' => -1
1892            ));
1893            $this->LessonOnair->closeDBReplica();
1894        }
1895
1896        //NJ-20590
1897        $teacher->image_url = myTools::checkAndReturnPresignedUrl($teacher->image_url);
1898
1899
1900        $hash = $this->request->query['chatHash'] ?? null;
1901        if(!empty($hash)){
1902            if (!class_exists('myMemcached')) {
1903                App::uses('myMemcached', 'Lib');
1904            }
1905            $memcached = new myMemcached();
1906            $appreciationDoneCache = $memcached->get("appreciation_done_".$hash);
1907            $this->set("isAppreciationDone", $appreciationDoneCache == 1 ? 1 : 0);
1908        }
1909
1910        // NJ-NJ-62396
1911        $isCallanTextbook = (!empty($textbook['TextbookCategories']['textbook_category_type']) && in_array($textbook['TextbookCategories']['textbook_category_type'], Configure::read('callan_textbook_type'))) ? 1 : 0;
1912
1913
1914        // NJ-3696
1915        // set view vars
1916        $setData = array(
1917            'textbookCategory' => $textbook['TextbookCategories'] ?? [],
1918            'teacher' => $teacher,
1919            'onair' => $oOnair,
1920            'isFav' => $isFav,
1921            'isHide' => $isHide,
1922            'ongoingLessonWithOtherStudentButtonDelay' => $ongoingLessonWithOtherStudentButtonDelay,
1923            'initialTeacherStatus' => $initialTeacherStatus,
1924            'teacherFavsColors' => $teacherFavsColors,
1925            'favoriteCount' => $favoriteCount,
1926            'tId' => $teacher->id,
1927            'user' => $user,
1928            'lessonAvailable' => isset($lessonAvailable['lessonAvailable']) ? $lessonAvailable['lessonAvailable'] : 0,
1929            'userMembership' => isset($userMembership)?$userMembership:'',
1930            'adminFlag' => isset($user['admin_flg'])?$user['admin_flg']:'0',
1931            'enquate6_options' => UserTable::getEnquate6(),
1932            'enquate7_options' => UserTable::getEnquate7(),
1933            'stusapLessonCount' => $stusapLessonCount,
1934            'lessonCount' => $lessonCount,
1935            'commentCount' => $commentCount,
1936            'userId' => $userId,
1937            'cardAuth' => PaymentTable::checkIfCardAuth($this->Auth->user('id'), $this->Auth->user('hash16')),
1938            'teacherCoin' => empty($teacherCoin)? 0: (int)$teacherCoin,
1939            'callanCoin' => (int)$callanCoin,
1940            'teacherCallanDiscount' => empty($teacherCallanDiscount)? 0: $teacherCallanDiscount,
1941            'isCallanTextbook' => $isCallanTextbook,
1942            'UserData' => $data,
1943            'userCountry' => $userCountry,
1944            'velifyCount' => $velifyCount,
1945            'firstTimeLoggedIn' => $firstTimeLoggedIn,
1946            'isLoggedIn' => $this->Auth->loggedIn(),
1947            'country' => $country,
1948            'timeDiff' => $timeDiff,
1949            'corporateId' => !empty($data['User']['corporate_id']) ? $data['User']['corporate_id'] : $this->Auth->user('corporate_id'),
1950            'translatedMessageParams' => $translatedMessageParams,
1951            'translatedSelfIntroductionThirdPpParams' => $translatedSelfIntroductionThirdPpParams,
1952            'translationModel' => $this->Translation,
1953            'weekly_ratings' => isset($get_weekly_rating['TeacherWeeklyRating']) ? $get_weekly_rating['TeacherWeeklyRating'] : 0,
1954            'hideLimitedPlanReservation' => $hideLimitedPlanReservation,
1955            'canCoinPurchase' => $canCoinPurchase,
1956            'liveStatus' => $liveStatus,
1957            'teacherCoinWithOp' => empty($teacherCoinWithOp)? 0: (int)$teacherCoinWithOp,
1958            'nativeOptionFlg' => $displayNativeOptionAmountFlg,
1959            'teacherCoinBeforeDiscount' => empty($teacherCoinBeforeDiscount)? 0: (int)$teacherCoinBeforeDiscount,
1960            'sapuriCoin' => $sapuriCoin,
1961            'isEmergencyPage' => !empty($this->request->query['emergency']) ? true : false,
1962            'teacherTitleThreshold' => $teacherTitleThreshold,
1963        );
1964
1965        $this->set($setData);
1966        if ($userId) {
1967            $points = $this->UsersPoint->find('first', array(
1968                'fields' => array('point'),
1969                    'conditions' => array(
1970                        'user_id' => $userId
1971                    )
1972                )
1973            );
1974
1975            $points = isset($points['UsersPoint']['point']) ? $points['UsersPoint']['point'] : 0;
1976            $reservePoint = Configure::read("reserve_point");
1977
1978            if (intval($reservePoint) < 1) $reservePoint = 0;
1979            //set promo discount for reservation
1980            // set paramater to 2 for reservation promo
1981            $bonus = CoinSetTable::getCoinSet(2);
1982            //check if the promo is valid today
1983            if ($bonus) {
1984                $reservePoint = $bonus;
1985            }
1986        } else {
1987            $points = 0;
1988        }
1989
1990        # get user timezone
1991        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
1992        $user_timezone_data = $this->Timezone->find('first',
1993            array(
1994                'fields' => array(
1995                    'Timezone.city_eng',
1996                    'Timezone.utc_offset',
1997                    'Timezone.country_code_id'
1998                ),
1999                'conditions' => array(
2000                    'Timezone.id' => $user_timezone_id
2001                ),
2002                'recursive' => -1
2003            )
2004        );
2005
2006        // - NJ-3653 get country
2007        $countryTimezone = null;
2008        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
2009            // - Get all country Code
2010            $countryOptions = $this->Timezone->countryOptions();
2011
2012            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
2013            $countryName = $countryOptions[$countryCodeId]['country_name'];
2014
2015            if (isset($countryName) && $countryName) {
2016                $countryTimezone = $countryName;
2017            }
2018        }
2019
2020        $this->set('countryTimezone', $countryTimezone);
2021        $this->set('userTimezoneData', $user_timezone_data);
2022
2023        #user time
2024        $datetime = date('Y-m-d H:i:s');
2025        $localTime = $this->displayTime;
2026        // NJ-29496
2027        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
2028            $formattedDate = date('d/m/Y G:i', $localTime);
2029        } else {
2030            $formattedDate = date('Y/m/d G:i', $localTime);
2031        }
2032        $this->set('userCurrentTime', $formattedDate);
2033
2034        $this->set('points', $points);
2035        $this->set('reservePoint', isset($reservePoint)? $reservePoint: 0);
2036
2037        $countrids_no = Configure::read('sms_send.countrids_no');
2038        $this->set('countrids_no', $countrids_no);
2039
2040        $deviceNotSupported = false;
2041        $ua = (!empty(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']))) ? myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) : '';
2042        if (strpos($ua, 'Android') !== false || strpos($ua, 'iPhone') !== false || strpos($ua, 'iPad') !== false || strpos($ua, 'iPod') !== false) {
2043            $deviceNotSupported = true;
2044        }
2045        $this->set('deviceNotSupported', $deviceNotSupported);
2046
2047        $userLang = !empty($this->localizeDir) ? $this->localizeDir : Configure::read('english_language_id');
2048        $languageIds = $this->CountryCode->getLanguageList(['field'=>'iso_639_1']);
2049        $getCRData = $this->Teacher->getCountryResidenceData($teacherId, $userLang, 'first', $languageIds);
2050        $residenceData = $this->getResidenceData($getCRData);
2051        $this->set('residenceData',$residenceData);
2052        $this->set('residenceFlg',$residenceData['countryFlag']);
2053        $this->set('deviceNotSupported', $deviceNotSupported);
2054        $this->set('statusCheck', array(1, 4));
2055
2056        $this->set('login', $this->Auth->loggedIn());
2057        $preset = array();
2058        if($this->Auth->User('id')) {
2059            //get preset textbook -> last viewed -> default textbook category first lesson
2060            $presetParams = array("user_id" => $this->Auth->User('id'));
2061
2062            //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
2063            $presetParams["userValidForSSBEDT"] = $this->userValidForSSBEDT();
2064            //add additional parameters
2065            if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
2066                $presetParams["lang"] = $this->localizeDir;
2067            }
2068
2069            #NC-9916
2070            if($data['User']) {
2071                $presetParams['native_language2'] = $userData->native_language2;
2072                $presetParams["userMembershipType"] = $userData->getMembershipTypeIndex();
2073            }
2074
2075            $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
2076            if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
2077                # for preset
2078                $presetParams['connect_id'] = $preset_data['preset_connect_id'];
2079                $presetParams['last_opened_date'] = $preset_data['preset_last_viewed_date'];
2080
2081            } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
2082                # use last viewed textbook if no preset data.
2083                $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
2084                $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
2085
2086            }
2087
2088            // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
2089            $presetParams['is_pc_flg'] = 1;
2090
2091            # fetch preset
2092            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
2093            if(!$preset) {
2094                unset($presetParams['connect_id']);
2095                unset($presetParams['last_opened_date']);
2096                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
2097            }
2098        }
2099
2100        //set variable preset textbook to be displayed
2101        $this->set('preset', $preset);
2102
2103        // NJ-8416: check for textbook live_lesson_flg is ON
2104        $textbookCategory = isset($preset['textbook_info']['TextbookCategory']) ? $preset['textbook_info']['TextbookCategory'] : array();
2105        $presetIsLiveTextbook = (isset($textbookCategory['live_lesson_flg']) && $textbookCategory['live_lesson_flg']) ? true : false;
2106        $this->set('presetIsLiveTextbook', $presetIsLiveTextbook);
2107
2108        // apology list (cancellation of reservation)
2109         $apologyList = array(); // NC-4749 : hide list, used function from model and made it popup modal
2110
2111         // -- NJ-18780: is normal lite plan user 
2112        $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
2113        $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
2114
2115        $this->set('apologyList', $apologyList);
2116        $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
2117            'userId' => $this->Auth->user('id'),
2118            'teacherId' => $teacherId,
2119            'timeDiff' => $this->timeDiff,
2120            'isNormalLitePlanUser' => $isNormalLitePlanUser
2121        ));
2122        $this->set('disabledSchedule', json_encode($disabledSchedule));
2123        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
2124        $this->set('noIndexFlgOveride', ($this->localizeDir != Configure::read('default.user_language') ? true : false));
2125        $this->set('isNormalLitePlanUser',$isNormalLitePlanUser);
2126
2127        //NC-7603 get keep memo
2128        $getKeepMemo = $this->UsersMemo->find('first', array(
2129            'fields' => array(
2130                'id',
2131                'memo'
2132            ),
2133            'conditions' => array(
2134                'user_id' => $this->Auth->user('id'),
2135                'teacher_id' => $teacherId,
2136                'type' => 0
2137            ),
2138            'order' => array('created DESC'),
2139        ));
2140
2141        $this->set('keep_memo', $getKeepMemo);
2142
2143        // NC-8020
2144        $this->set('textbookConnectId', $preset['textbook_connect_id']);
2145        $this->set('textbookCategoryTypeId', $preset['textbook_type']);
2146
2147        // - NJ-6390 add highLightFlag
2148        $this->set('highLightFlag', isset($highLightFlag) && $highLightFlag? $highLightFlag: null);
2149
2150        // NJ-42
2151        $liveCoin = $this->LessonOnairsViewer->getLiveLessonCoinPrice(['current_rank_id' => $teacher->current_rank_id]);
2152        $this->set('liveCoin', number_format((float)$liveCoin));
2153
2154        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
2155        //NC-7984 start
2156        $lesson_history_data = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir);
2157        if(!empty($lesson_history_data)) {
2158            $this->set('lessonHistory', $lesson_history_data['lessonHistory']);
2159            $this->set('textbookNamesCachedArr', $lesson_history_data['textbookNamesCachedArr']);
2160        }
2161        //NC-7984 end
2162        
2163        $showRating = $teacher->getReviewOption($teacher->rank_coin_id);
2164        $this->set('showRating', $showRating);
2165
2166        //NJ-20069 teacher
2167        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
2168        $lessonHistory = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, null);
2169        $lessonHistoryCount  = count($lessonHistory['lessonHistory']);
2170        $latestUserLesson = isset($lessonHistory['lessonHistory'][0]['LessonOnairsLog']) ? $lessonHistory['lessonHistory'][0]['LessonOnairsLog'] : null;
2171        $teacherFavoriteCount = $this->UsersFavorite->getFavoriteCount($teacherId);
2172        
2173        // - if has translated Category name
2174        if (isset($lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) && $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) {
2175            $lessonHistory['lessonHistory'][0]['TextbookCategory']['name'] = $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name'];
2176        }
2177        
2178        $formattedLatestLessonData = "";
2179        if(!empty($latestUserLesson))
2180        $formattedLatestLessonData = date('Y-m-d',strtotime($latestUserLesson['start_time'])). " (" . date('D',strtotime($latestUserLesson['start_time'])) . ") ";
2181        
2182        $teacherLastLogin = $teacher->last_login_time;
2183        $formattedTeacherLastLogin = "";
2184        if(!empty($teacherLastLogin)) {
2185            if ($this->localizeDir == 'pt-br') {
2186                $daysOfWeekPtBr = [
2187                    'Sun' => __dx('account', 'week', '日'), // Dom
2188                    'Mon' => __dx('account', 'week', '月'), // Seg
2189                    'Tue' => __dx('account', 'week', '火'), // Ter
2190                    'Wed' => __dx('account', 'week', '水'), // Qua
2191                    'Thu' => __dx('account', 'week', '木'), // Qui
2192                    'Fri' => __dx('register', 'week', '金'), // Sex
2193                    'Sat' => __dx('account', 'week', '土')  // Sab
2194                ];
2195                $dayOfWeekPtBr = $daysOfWeekPtBr[date('D', strtotime($teacherLastLogin))];
2196        $formattedTeacherLastLogin = date('d/m/Y', strtotime($teacherLastLogin)) . " ({$dayOfWeekPtBr}";
2197            } else {
2198                $formattedTeacherLastLogin = date('Y-m-d',strtotime($teacherLastLogin)). " (" . date('D',strtotime($teacherLastLogin)) . ") ";
2199            }
2200        }
2201
2202        $this->set('lessonHistoryCount', $lessonHistoryCount);
2203        $this->set('latestUserLesson', isset($lessonHistory['lessonHistory'][0]) ? $lessonHistory['lessonHistory'][0] : null);
2204        $this->set('teacherRates', $reserveAndCancel);
2205        $this->set('teacherIdCheck', $teacherId);
2206        $this->set('latestLessonData', $formattedLatestLessonData);
2207        $this->set('teacherLastLogin', $formattedTeacherLastLogin);
2208        $this->set('teacherFavoriteCount', $teacherFavoriteCount);
2209
2210        $this->TeacherFeature->openDBReplica();
2211        $teacherFeatures = $this->TeacherFeature->find('first', array(
2212            'conditions' =>  array(
2213                'TeacherFeature.teacher_id' => $teacherId
2214            )
2215        ));
2216        $this->TeacherFeature->closeDBReplica();
2217        
2218        # NJ-19429: fetch campaign
2219        $studentID = $this->Auth->user('id');
2220        $inCampaignDetails = $this->CampaignInstructor->getValidateUserCampaign($teacherId, $studentID);
2221
2222        //NJ-47494 - add 8 day checker for campaign
2223        $now = date('Y-m-d');
2224        $dayTimer = date('Y-m-d', strtotime('+7 days'));
2225        
2226        $inCampaignStartDate = isset($inCampaignDetails['CampaignInstructor']['start_date']) ? date('Y-m-d', strtotime($inCampaignDetails['CampaignInstructor']['start_date'])) : null;
2227        $inCampaignEndDate = isset($inCampaignDetails['CampaignInstructor']['end_date']) ? date('Y-m-d', strtotime($inCampaignDetails['CampaignInstructor']['end_date'])) : null;
2228        $validCampaignDate = !($dayTimer < $inCampaignStartDate || $now > $inCampaignEndDate);
2229
2230        if ($inCampaignDetails && $validCampaignDate == 1){
2231            $campaign = $inCampaignDetails['CampaignInstructor'];
2232
2233            $campaignTag = '';
2234            if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { // if the language is Custom language format
2235                $campaignTag .= $campaign['discount'] == 100 ? '100% OFF ' : '50% OFF ';
2236                $campaignTag .= '(' . __d('waiting',Configure::read('campaign_instructor_textbook_type')[$campaign['textbook_type']]) . ') ';    
2237
2238                // NJ-47838 GGPE FB10
2239                if((int) $campaign['classification'] == 4) {
2240                    $campaignTag = __d('waiting', Configure::read('campaign_instructor_tags')[$campaign['campaign_tag_id']]);
2241                }
2242            } else { // if the language is not Custom language format
2243                $campaignTag .= $campaign['discount'] == 100 ? '100%OFF ' : '50%OFF ';
2244                $campaignTag .= '('.Configure::read('campaign_instructor_textbook_type')[$campaign['textbook_type']]. ') ';
2245                $campaignTag .= Configure::read('campaign_instructor_type')[$campaign['classification']] . '講師';
2246            }
2247
2248            $teacherFeatures['CampaignTag'] = $campaignTag;
2249
2250            // NJ-47838
2251            $teacherFeatures['CampaignTagClassification'] = $campaign['classification'];
2252            // NJ-47838 : Set a flag if the campaign is classified as "Live"
2253            $teacherFeatures['IsCampaignLive'] = ($campaign['classification'] === 4);
2254
2255            // NJ-47838 : Ensure the campaign discount is set if the campaign is live and the teacher is registered for it
2256            if ($teacherFeatures['IsCampaignLive']) {
2257                $teacherFeatures['CampaignLiveDiscount'] = $campaign['discount'];
2258            }
2259        }
2260
2261        if(isset($campaign) && $campaign){
2262            $this->set('campaignDiscount', isset($campaign['discount']) ? $campaign['discount'] : null);
2263            $this->set('campaignTextbook', isset($campaign['textbook_type']) ? $campaign['textbook_type'] : null);
2264            $this->set('campaignDiscountClassification', isset($campaign['classification']) ? $campaign['classification'] : null);
2265        }
2266
2267        $this->set('teacherFeatures', $teacherFeatures);
2268        
2269        // NJ-3786 textbook teacher recommendation
2270        $curDate = date('Y-m-d');
2271        $userId = $this->Auth->user('id') ? $this->Auth->user('id') : null;
2272        $txtTeacherRecommendlimit = 10;
2273        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
2274        $endDate = date('Y-m-d',strtotime('-1 day' ,strtotime($curDate)));
2275        $beginDate = date('Y-m-d',strtotime('-1 month' ,strtotime($curDate)));
2276
2277        if( $userId ) {
2278            // - NJ-8416: check for last lesson type
2279            $lastLessonType = ClassRegistry::init('LessonOnair')->getLastLessonType($userId);
2280            $this->log('[NJ-8416 lastLessonType waitingDetail] -> ' . json_encode($lastLessonType), 'debug');
2281            $lastBookUsedData = $this->UsersTextbookInfo->getCurrentTextbookAndBadgeData( array( 
2282                'user_id' => $userId,
2283                'limit' => 10, // waiting detail page
2284                'last_lesson_type' => $lastLessonType
2285            ) );
2286            $textbookCategoryId = $lastBookUsedData['category_id'];
2287            $textbookBadge = $lastBookUsedData['textbook_badge'];
2288            $this->log('[NJ-8416 textbookCategoryId waitingDetail] -> ' . json_encode($textbookCategoryId), 'debug');
2289            $paramsArr = array(
2290                'user_id' => $userId,
2291                'begin_date' => $beginDate,
2292                'end_date' => $endDate,
2293                'textbook_category' => $textbookCategoryId,
2294                'textbook_badge' => $textbookBadge,
2295                'limit' => $txtTeacherRecommendlimit,
2296                'user_data' => $userData,
2297                'exclude_teacher_id' => $teacherId
2298            );
2299
2300            $teacherTextbookStatData = $this->TeacherTextbookStat->fetchTextbookTeacherRatingData($paramsArr);
2301            if( $teacherTextbookStatData ) {
2302                $dataList = $this->arrangeTeacherRecommendList( array( 
2303                        'user_id' => $userId,
2304                        'data' => $teacherTextbookStatData,
2305                        'category_id' => $textbookCategoryId,
2306                        'user_data' => $userData
2307                    ) 
2308                );
2309                $this->set('textbookTeacherData', $dataList);
2310            }
2311        }
2312
2313        $ownReservationTeacherData = $this->LessonSchedule->getWaitingToJoinReservationTeacherInfo( array( 'user_id' => $this->Auth->user('id'), 'limit_checker_flag' => 1 ) );
2314        $this->set( 'ownReservationTeacherId', $ownReservationTeacherData['teacher_id'] ); // live lesson work-around
2315        $this->set( 'lessonScheduleOwnReservationTeacher', isset($lessonScheduleOwnReservationTeacherData['teacher_id']) ? $lessonScheduleOwnReservationTeacherData['teacher_id'] : null ); // live lesson work-around
2316        $this->set( 'studentDelayInSeconds', (int)$studentDelayInSeconds );
2317        $this->set( 'remainingSeconds', (int)$remainingSeconds );
2318        $this->set( 'ownReservationFlg', $ownReservationFlg );
2319        $this->set( 'teacherStatusColor', $teacherStatusColor );
2320
2321        if ($this->request->query('chatHash')) {
2322            $chatHash = $this->request->query('chatHash');
2323
2324            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
2325            $this->set('data',  $allData);
2326
2327            $friParams = array(
2328                'type' => 0,
2329                'langId' => $this->CountryCode->getUserLanguageId($this->localizeDir),
2330                'from' => 'user'
2331            );
2332
2333            $strengthItems = $this->FeatureRatingItem->getActiveItems($friParams);
2334
2335            // get active weakness feature rating items
2336            $friParams['type'] = 1;
2337            $weaknessItems = $this->FeatureRatingItem->getActiveItems($friParams);
2338
2339            $this->set('strengthItems', $strengthItems);
2340            $this->set('weaknessItems', $weaknessItems);
2341            
2342            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
2343
2344            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
2345                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
2346
2347                if(!$allData) {
2348                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
2349                }
2350            }
2351
2352            $this->set('data',  $allData);
2353
2354            $live_lesson_viewer = 0;
2355            if((!empty($allData['LessonOnairsLog']) && $allData['LessonOnairsLog']['live_lesson_flg'] == 1 && $allData['LessonOnairsLog']['user_id'] != $userId)
2356                || (!empty($allData['LessonOnair']) && $allData['LessonOnair']['live_lesson_flg'] == 1 && $allData['LessonOnair']['user_id'] != $userId)
2357            ) { $live_lesson_viewer = 1; }
2358            
2359            // get last feature rating items
2360            if($live_lesson_viewer){
2361                $lastRatingItems = $this->ViewerFeatureRatingLastVoted->getLastEvalItems(array('teacherId' => $teacherId, 'userId' => $userId));
2362            } else {
2363                $lastRatingItems = $this->UserFeatureRatingLastVoted->getLastEvalItems(array('teacherId' => $teacherId, 'userId' => $userId));
2364            }
2365            
2366            $this->set('lastSelectedStrengthItems', isset($lastRatingItems['strengthItems']) ? $lastRatingItems['strengthItems'] : array());
2367            $this->set('lastSelectedWeaknessItems', isset($lastRatingItems['weaknessItems']) ? $lastRatingItems['weaknessItems'] : array());
2368
2369            $userValidForSSBEDT = false;
2370            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
2371                $userValidForSSBEDT = true;
2372            }
2373            $param = array(
2374                "user_id" => $userId,
2375                "select_method" => "first",
2376                "env_flag" => "all",
2377                'connect_id' => $allData['Connect']['id'],
2378                "user_locale" => $this->localizeDir,
2379                "userValidForSSBEDT" => $userValidForSSBEDT
2380            );
2381            //NJ-12326
2382            if ($userId && isset($allData['Connect']['category_id']) && $allData['Connect']['category_id']) {
2383                $corporateParams = array('user_id' => $userId);
2384                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
2385                
2386                if ($corporateTextbookControlFlg == 1) {
2387                    $categoryData = $this->TextbookCategory->getKidsCategoryTypesById($allData['Connect']['category_id']);
2388                    if (!empty($categoryData)) {
2389                        $param['include_kids_category'] = $allData['Connect']['category_id'];
2390                    }
2391                }
2392            }
2393            $textbookData = $this->Textbook->getTextbooks($param);
2394            $data = $textbookData['res_data'];
2395
2396            $isReservedLesson = 2;
2397            $hideTextbookChangeModal = $enableNextTextbookChapterButton = 'false';
2398            $latestPresetTextbookConnect_id = (int)$data['TextbookConnect']['id'];
2399            $latestPresetTextbookConnect_categoryId = (int)$data['TextbookConnect']['category_id'];
2400            $latestPresetTextbookConnect_subCategoryId = (int)$data['TextbookConnect']['subcategory_id'];
2401            $latestPresetTextbookCategory_textbookCatType = (int)$data['TextbookCategory']['textbook_category_type'];
2402
2403            //NJ-3626 Optimize PC /lesson-finish page
2404            $lessonOnairLatestData = $this->LessonOnair->getLatestLessonOnairDetailsOfUserAndTeacher($userId, $teacherId);
2405            if(isset($lessonOnairLatestData) && $lessonOnairLatestData) {
2406                $lessonOnairLatestDataFlg = true;
2407                $lessonOnairLatest_connectId = (int)$lessonOnairLatestData['LessonOnair']['connect_id'];
2408                $lessonOnairLatest_lessonType = (int)$lessonOnairLatestData['LessonOnair']['lesson_type'];
2409            } else {
2410                $lessonOnairLogsLatestData = $this->LessonOnairsLog->getLatestLessonLogsDetailsOfUserAndTeacher($userId, $teacherId);
2411                if(isset($lessonOnairLogsLatestData) && $lessonOnairLogsLatestData) {
2412                    $lessonOnairLogsLatest_connectId = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['connect_id'];
2413                    $lessonOnairLogsLatest_lessonType = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['lesson_type'];
2414                }
2415            }
2416
2417            // - initialize empty variable
2418            $isLatestPresetTextbookMadeDuringLastLesson = [];
2419            $latestPresetTextbookParams = [];
2420
2421            // For hiding of textbookchange modal (if reserved lesson & not studySapuri)
2422            if ($lessonOnairLatestDataFlg) {
2423                $latestPresetTextbookParams = array (
2424                    'userId' => $userId,
2425                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
2426                    'lessonOnairLatest_startTime' => $lessonOnairLatestData['LessonOnair']['start_time'],
2427                    'lessonOnairLatest_endTime' => $lessonOnairLatestData['LessonOnair']['end_time']
2428                );
2429
2430            // - if has lesson onairs log
2431            } else if ($lessonOnairLogsLatestData) {
2432                $latestPresetTextbookParams = array (
2433                    'userId' => $userId,
2434                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
2435                    'lessonOnairLogsLatest_startTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['start_time'],
2436                    'lessonOnairLogsLatest_endTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['end_time']
2437                );
2438
2439            }
2440            
2441            // - if has parameters for fetching latest textbook parameters
2442            if ($latestPresetTextbookParams) {
2443                $isLatestPresetTextbookMadeDuringLastLesson = $this->UsersTextbookInfo->checkLatestUserTextbookInfoChangedDuringLesson($latestPresetTextbookParams);
2444            }
2445
2446            // -  check sapuri ID
2447            if(!isset($this->studySapuriId) || !$this->studySapuriId) {
2448                if (isset($lessonOnairLatestDataFlg)) {
2449                    if (is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
2450                        && $latestPresetTextbookConnect_id == $lessonOnairLatest_connectId && $lessonOnairLatest_lessonType == $isReservedLesson
2451                    ) {
2452                        $hideTextbookChangeModal = 'true';
2453                    }
2454                } else {
2455                    if (
2456                        is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
2457                        && $latestPresetTextbookConnect_id == $lessonOnairLogsLatest_connectId &&  $lessonOnairLogsLatest_lessonType == $isReservedLesson
2458                    ) {
2459                        $hideTextbookChangeModal = 'true';
2460                    }
2461                }
2462            }
2463
2464            $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
2465
2466            $this->set('hideTextbookChangeModal', $hideTextbookChangeModal);
2467
2468            // For enabling next textbook chapter button (if not callan and not ongoing lesson)
2469            if (
2470                $hideTextbookChangeModal == 'false'
2471                && (isset($latestPresetTextbookCategory_textbookCatType) &&  !in_array($latestPresetTextbookCategory_textbookCatType, Configure::read('callan_textbook_type')))
2472                && (isset($onGoingLesson) && $onGoingLesson == false)
2473            ) {
2474                $allTextbookParams = array(
2475                    'category_id' => $latestPresetTextbookConnect_categoryId, 
2476                    'connect_id' => $latestPresetTextbookConnect_id,
2477                    'subcategory_id' => $latestPresetTextbookConnect_subCategoryId
2478                );
2479                
2480                $allTextbookChapters = $this->TextbookConnect->getTextbookPrevAndNextFunction($allTextbookParams);
2481                // if has next textbook chapter, show button 
2482                if (
2483                    is_array($allTextbookChapters) && !is_null($allTextbookChapters) 
2484                    && ($allTextbookChapters['next'] !== '' && !is_null($allTextbookChapters['next']))
2485                ) {
2486                    $enableNextTextbookChapterButton = 'true';
2487                }
2488            }
2489
2490            if(!empty($this->sharedUserData['User'])){
2491                // - campaing stamps
2492                $this->getActiveCampaignStampData();
2493            }
2494
2495            $this->set('enableNextTextbookChapterButton', $enableNextTextbookChapterButton);
2496        }
2497
2498        //NJ-18780 : check the user total reservation if lite plan 
2499        $_user = $this->sharedUserData['User'] ?? array();
2500        $liteLimitReservationFlg = 0;
2501
2502        if (
2503            $_user && 
2504            in_array($_user['payment_plan_id'], Configure::read('lite_payment_plans'))
2505        ) {
2506            # fetch the total reservation 
2507            $liteUserReservationCount = $this->LessonSchedule->countUserTotalReservation(array('userId' => $this->Auth->user('id')));
2508
2509            if ($liteUserReservationCount >= Configure::read("lite_plan_maximum_number_of_total_reservation")) {
2510                # show modal
2511                $liteLimitReservationFlg = 1;
2512            }
2513        }
2514
2515        // NJ-18780 : set view 
2516        $this->set('liteLimitReservationFlg',$liteLimitReservationFlg);
2517
2518
2519        $this->set('chatHash', isset($chatHash) ? $chatHash : '');
2520    
2521        //-Live Lesson Phase 3
2522        $this->set('liveLessonFlg', $liveLessonFlg);
2523
2524        //NJ-33414
2525        $this->UsersDetail->openDBReplica();
2526        $fetchUsersDetail = $this->UsersDetail->find('first', array(
2527            'fields' => array(
2528                'lesson_request_flg'
2529            ),
2530            'conditions' =>  array('user_id' => $this->sharedUserData['User']['id']),
2531            'recursive' => -1
2532        ));
2533        $this->UsersDetail->closeDBReplica();
2534
2535        $lessonRequestFlg = $fetchUsersDetail ? $fetchUsersDetail['UsersDetail']['lesson_request_flg'] : 1;
2536        $this->set('lessonRequestFlg',$lessonRequestFlg);
2537
2538        //-- NJ-44869 skip communication modal
2539        $lessonSystemTroubleFlg = 0;
2540        $hideConnectionModalFlg = 0;
2541
2542        if (!empty($chatHash)) {
2543            $memcached = new myMemcached();
2544            $lessonSystemTroubleCache = $memcached->get('lesson_system_trouble_' . $chatHash);
2545    
2546            if (!empty($lessonSystemTroubleCache)) {
2547                $memcached->delete('lesson_system_trouble_' . $chatHash);
2548                $lessonSystemTroubleFlg = 1;
2549            } 
2550        }
2551        
2552        $this->set('lessonSystemTroubleCache', $lessonSystemTroubleFlg);
2553        $this->set('hideConnectionModalFlg', $hideConnectionModalFlg);
2554    }
2555
2556    /**
2557     * @api {post} /user/waiting/getStrengthRating getStrengthRating()
2558     * @apiName getStrengthRating
2559     * @apiGroup Waiting
2560     * @apiDescription Retrieves the strength rating items for a specific teacher in Native Camp. It returns the list of strength rating items.
2561     *
2562     * @apiBody {String} teacherId The ID of the teacher.
2563     * 
2564     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2565     * @apiSuccess {Object[]} strengthItems The list of strength rating items.
2566     *
2567     * @apiSuccessExample {json} Success-Response:
2568     *     {
2569     *         "res": true,
2570     *         "strengthItems": [
2571     *             {
2572     *                 "id": 1,
2573     *                 "name": "Friendly",
2574     *                 "rating": 5
2575     *             }
2576     *         ]
2577     *     }
2578     *
2579     * @apiError {Boolean} res Indicates whether the request was successful.
2580     *
2581     * @apiErrorExample {json} Error-Response:
2582     *     {
2583     *         "res": false
2584     *     }
2585     * 
2586     * @apiSampleRequest off
2587     */
2588    public function getStrengthRating() {
2589        $this->autoRender = false;
2590        $this->layout = false;
2591        $response = json_encode(array('res' => false)); // default
2592
2593        if($this->request->is('post')) {
2594            $post = $this->request->data;
2595            if (!isset($post['teacherId']) && $post['teacherId']) {
2596                return json_encode($response);
2597            }
2598            $teacherId = $post['teacherId'];
2599            
2600            $strengthItemsParams = array(
2601                'teacherId' => $teacherId,
2602                'type' => 0,
2603                'langId' => $this->CountryCode->getUserLanguageId($this->localizeDir)
2604            );
2605
2606            $strengthItems = $this->TeacherFeatureRating->getFeatureRatingItems($strengthItemsParams);
2607            
2608            if(!empty($strengthItems) && $strengthItems) {
2609                $response = json_encode(array(
2610                    'res' => true, 
2611                    'strengthItems' => $strengthItems, 
2612                ));
2613            }
2614        }
2615        return $response;
2616
2617    }
2618
2619    /**
2620     * @api {post} /user/waiting/getLessonHistory getLessonHistory()
2621     * @apiName getLessonHistory
2622     * @apiGroup Waiting
2623     * @apiDescription Retrieves the lesson history for a specific teacher and user in Native Camp. It returns the details of the lessons, including textbook information and chat logs.
2624     *
2625     * @apiBody {String} teacherId The ID of the teacher.
2626     * @apiBody {Boolean} [avatar_flg=false] Indicates if the request is for avatar lessons.
2627     * 
2628     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2629     * @apiSuccess {Object[]} lessonHistory The list of lesson history.
2630     * @apiSuccess {Number} lessonHistory.lesson_number The lesson number.
2631     * @apiSuccess {String} lessonHistory.chatStartJPDate The start date of the chat in JP format.
2632     * @apiSuccess {String} lessonHistory.chatStartTime The start time of the chat.
2633     * @apiSuccess {String} lessonHistory.lessonHistoryTime The duration of the lesson.
2634     * @apiSuccess {String} lessonHistory.textbook_url The URL of the textbook.
2635     * @apiSuccess {String} lessonHistory.categoryNameLabel The category name of the textbook.
2636     * @apiSuccess {String} lessonHistory.subCategoryNameLabel The subcategory name of the textbook.
2637     * @apiSuccess {String} lessonHistory.textbookNameLabel The name of the textbook.
2638     * @apiSuccess {Number} lessonHistory.rate The rating of the lesson.
2639     * @apiSuccess {String} lessonHistory.chat_logs_url The URL of the chat logs.
2640     * @apiSuccess {Boolean} lessonHistory.has_message_logs Indicates if the lesson has message logs.
2641     * @apiSuccess {String} lessonHistory.message_logs_url The URL of the message logs.
2642     * @apiSuccess {Number} lessonHistory.audio_count_log The audio count log.
2643     * @apiSuccess {String} lessonHistory.textbook_image The image URL of the textbook.
2644     *
2645     * @apiSuccessExample {json} Success-Response:
2646     *     {
2647     *         "res": true,
2648     *         "lessonHistory": [
2649     *             {
2650     *                 "lesson_number": 1,
2651     *                 "chatStartJPDate": "2023-12-01",
2652     *                 "chatStartTime": "10:00",
2653     *                 "lessonHistoryTime": "30分",
2654     *                 "textbook_url": "/textbook/page-detail/1/123",
2655     *                 "categoryNameLabel": "Category Name",
2656     *                 "subCategoryNameLabel": "Subcategory Name",
2657     *                 "textbookNameLabel": "Textbook Name",
2658     *                 "rate": 5,
2659     *                 "chat_logs_url": "/chat-history/123/abc123",
2660     *                 "has_message_logs": true,
2661     *                 "message_logs_url": "/lesson-message/detail/1",
2662     *                 "audio_count_log": 3,
2663     *                 "textbook_image": "http://example.com/image.jpg"
2664     *             }
2665     *         ]
2666     *     }
2667     *
2668     * @apiError {Boolean} res Indicates whether the request was successful.
2669     *
2670     * @apiErrorExample {json} Error-Response:
2671     *     {
2672     *         "res": false
2673     *     }
2674     * 
2675     * @apiSampleRequest off
2676     */
2677    public function getLessonHistory($sp = false, $teacherId = null) {
2678        $this->autoRender = false;
2679        $this->layout = false;
2680        $response = json_encode(array('res' => false)); // default
2681        
2682        if($this->request->is('post') || $sp) {
2683            $post = $this->request->data;
2684            if (!isset($post['teacherId']) && $post['teacherId']) {
2685                return json_encode($response);
2686            }
2687            $teacherId = $post['teacherId'] ?? $teacherId;
2688            $teacherId = Sanitize::escape($teacherId);
2689
2690            $isAvatarFlg = (isset($post['avatar_flg']) && $post['avatar_flg']) ? true : false;
2691
2692            //NC-7984 start
2693            if($isAvatarFlg){
2694                $lesson_history_data = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, 10, "avatar");
2695            }else{
2696                $lesson_history_data = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, 10);
2697
2698            }
2699
2700            if(!empty($lesson_history_data) && $lesson_history_data) {
2701                $textbookNamesCachedArr = $lesson_history_data['textbookNamesCachedArr'];
2702
2703                foreach ($lesson_history_data['lessonHistory'] as $key => $value) {
2704                    $dteStart = new DateTime($value['LessonOnairsLog']['start_time']);
2705                    $dteEnd   = new DateTime($value['LessonOnairsLog']['end_time']);
2706
2707                    $logDetail = new LessonOnairsLogTable($value['LessonOnairsLog']);
2708
2709                    $lessonTime = $dteStart->diff($dteEnd);
2710                    $lessonHistoryTime = $lessonTime->format("%I");
2711
2712                    $textbookOrder = isset($textbookNamesCachedArr[$value['TextbookConnect']['id']]['order']) ? $textbookNamesCachedArr[$value['TextbookConnect']['id']]['order'] : '';
2713
2714                    $categoryName = $value['TextbookCategory']['name'];
2715                    $subcategoryName = $value['TextbookSubategory']['name'];
2716                    $textbookName = $value['Textbook']['name'];
2717                    $textbookMainTopicName = isset($value['Textbook']['main_topic_name']) ? $value['Textbook']['main_topic_name'] : '';
2718
2719                    // - if has translated Category name
2720                    if (isset($value['GlobalTextbookCategory']['gl_name']) && $value['GlobalTextbookCategory']['gl_name']) {
2721                        $categoryName = $value['GlobalTextbookCategory']['gl_name'];
2722                    }
2723
2724                    // - if has translated subcategory name
2725                    if (isset($value['GlobalTextbookSubcategory']['gl_name']) && $value['GlobalTextbookSubcategory']['gl_name']) {
2726                        $subcategoryName = $value['GlobalTextbookSubcategory']['gl_name'];
2727                    }
2728
2729                    // - if has translated textbook name
2730                    if (isset($value['GlobalTextbook']['gl_name']) && $value['GlobalTextbook']['gl_name']) {
2731                        $textbookName = $value['GlobalTextbook']['gl_name'];
2732                    }
2733
2734                    // - set textbook name
2735                    $categoryNameLabel = $categoryName;
2736                    $subCategoryNameLabel = $subcategoryName;
2737                    $subCategoryNameLabel = $textbookMainTopicName ? $textbookMainTopicName : $subcategoryName;
2738                    $textbookNameLabel = $textbookOrder . $textbookName;
2739                    $textbook_url = "/textbook/page-detail/{$value['TextbookCategory']['type_id']}/{$value['LessonOnairsLog']['connect_id']}";
2740
2741                    $has_message_logs = !empty($value['LessonOnairsLog']['lesson_memo']) && $value['LessonOnairsLog']['lesson_memo_disp_flg'] == 1 && $value['LessonOnairsLog']['display_message'] == 1;
2742                    $message_logs_url = "/lesson-message/detail/{$value['LessonOnairsLog']['id']}";
2743                    $teacher_id = $value['LessonOnairsLog']['teacher_id'];
2744                    $chat_logs_url = "/chat-history/{$teacher_id}/{$value['LessonOnairsLog']['chat_hash']}";
2745
2746                    $lesson_history_data['lessonHistory'][$key]['lesson_number'] = $value['LessonTrackLogs']['lesson_number'];
2747                    $lesson_history_data['lessonHistory'][$key]['chatStartJPDate'] = $logDetail->chatStartJPDate($this->timeDiffSecond);
2748                    $lesson_history_data['lessonHistory'][$key]['chatStartTime'] = $logDetail->chatStartTime($this->timeDiffSecond);
2749                    $lesson_history_data['lessonHistory'][$key]['lessonHistoryTime'] = $lessonHistoryTime. __('分');
2750                    $lesson_history_data['lessonHistory'][$key]['textbook_url'] = $textbook_url;
2751                    $lesson_history_data['lessonHistory'][$key]['categoryNameLabel'] = $categoryNameLabel;
2752                    $lesson_history_data['lessonHistory'][$key]['subCategoryNameLabel'] = $subCategoryNameLabel;
2753                    $lesson_history_data['lessonHistory'][$key]['textbookNameLabel'] = $textbookNameLabel;
2754                    $lesson_history_data['lessonHistory'][$key]['rate'] = $value['usersClassEvaluations']['rate'];
2755                    $lesson_history_data['lessonHistory'][$key]['chat_logs_url'] = $chat_logs_url;
2756                    $lesson_history_data['lessonHistory'][$key]['has_message_logs'] = $has_message_logs;
2757                    $lesson_history_data['lessonHistory'][$key]['message_logs_url'] = $message_logs_url;
2758                    $lesson_history_data['lessonHistory'][$key]['audio_count_log'] = $value['LessonOnairsLog']['temp_flg1'];
2759                    $lesson_history_data['lessonHistory'][$key]['textbook_image'] = $value['TextbookCategory']['image_big_url'];
2760                }
2761                
2762                $response = json_encode(array(
2763                    'res' => true, 
2764                    'lessonHistory' => $lesson_history_data['lessonHistory']
2765                ));
2766
2767                if($sp) {
2768                    $response = $lesson_history_data['lessonHistory'];
2769                }
2770            }
2771            //NC-7984 end
2772        }
2773
2774        return $response;
2775
2776    }
2777
2778    /**
2779     * @api {post} /user/waiting/getPrimaryDetails getPrimaryDetails()
2780     * @apiName getPrimaryDetails
2781     * @apiGroup Waiting
2782     * @apiDescription Retrieves the primary details for a specific teacher in Native Camp. It returns the number of lessons, reservations, and comments for the teacher.
2783     *
2784     * @apiBody {String} teacherId The ID of the teacher.
2785     * 
2786     * @apiSuccess {Number} lessonCount The number of lessons for the teacher.
2787     * @apiSuccess {Number} reserveCount The number of reservations for the teacher.
2788     * @apiSuccess {Number} commentCount The number of comments for the teacher.
2789     *
2790     * @apiSuccessExample {json} Success-Response:
2791     *     {
2792     *         "lessonCount": 100,
2793     *         "reserveCount": 50,
2794     *         "commentCount": 20
2795     *     }
2796     *
2797     * @apiError {String} status The status of the request (NG).
2798     * @apiError {String} message The error message.
2799     *
2800     * @apiErrorExample {json} Error-Response:
2801     *     {
2802     *         "status": "NG",
2803     *         "message": "Invalid request."
2804     *     }
2805     * 
2806     * @apiSampleRequest off
2807     */
2808    public function getPrimaryDetails() {
2809        $this->autoRender = false;
2810        $this->layout = "";
2811        if (!$this->request->is('ajax')) { return ; }
2812        
2813        $teacherId = $this->request->data['teacherId'];
2814        $teacherId = Sanitize::escape($teacherId);
2815        
2816        if (empty($teacherId)) { return ; }
2817
2818        //number of lesson for all child accounts
2819        $lessonCount = $this->LessonOnairsLog->countTeacherLessons(['teacherId' => $teacherId, 'avatar' => 1]);
2820        //number of reservation for all child accounts
2821        $reserveCount = $this->LessonSchedule->countTeacherReservedLessons(array('teacherId' => $teacherId, 'avatar' => 1));
2822
2823        $options = $this->Auth->user('id') ? array('userId' => $this->Auth->user('id')) : array();
2824        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir,true);
2825        $options['language_id'] = $reviewLanguage[0];
2826        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
2827        $options['isAvatar'] = 1;
2828
2829        $userTable = new UserTable($this->Auth->user());
2830        $sapuriPlan = $userTable->isStudySapuri();
2831        $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
2832        if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
2833            $options['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
2834        } else {
2835            $options['textbook_category_type_not_in'] = $sapuriTextbookType;
2836        }
2837
2838        $commentCount = $this->UsersClassEvaluation->getCommentCount($teacherId, $options);
2839        $results = [
2840            'lessonCount' => $lessonCount,
2841            'reserveCount' => $reserveCount,
2842            'commentCount' => $commentCount,
2843        ];
2844
2845        echo json_encode($results);
2846        return;
2847    }
2848
2849    /**
2850     * @api {post} /user/waiting/getFavCount getFavCount()
2851     * @apiName getFavCount
2852     * @apiGroup Waiting
2853     * @apiDescription Retrieves the favorite count for a specific teacher in Native Camp. It returns the total number of favorites and whether the current user has favorited the teacher.
2854     *
2855     * @apiBody {String} teacherId The ID of the teacher.
2856     * 
2857     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2858     * @apiSuccess {Number} favCount The total number of favorites for the teacher.
2859     * @apiSuccess {Number} isFav Indicates whether the current user has favorited the teacher (1: Yes, 0: No).
2860     *
2861     * @apiSuccessExample {json} Success-Response:
2862     *     {
2863     *         "res": true,
2864     *         "favCount": 10,
2865     *         "isFav": 1
2866     *     }
2867     *
2868     * @apiError {Boolean} res Indicates whether the request was successful.
2869     *
2870     * @apiErrorExample {json} Error-Response:
2871     *     {
2872     *         "res": false
2873     *     }
2874     * 
2875     * @apiSampleRequest off
2876     */
2877    public function getFavCount() {
2878        $this->autoRender = false;
2879        $this->layout = false;
2880        $response = json_encode(array('res' => false)); // default
2881
2882        if($this->request->is('post')) {
2883            $post = $this->request->data;
2884            if (!isset($post['teacherId']) && $post['teacherId']) {
2885                return json_encode($response);
2886            }
2887            $teacherId = $post['teacherId'];
2888
2889            $favCount = $this->UsersFavorite->find('count', array(
2890                'conditions' => array(
2891                    'UsersFavorite.teacher_id'  => $teacherId
2892                )
2893            ));
2894
2895            $isFav = $this->UsersFavorite->find('count', array(
2896                'conditions' => array(
2897                    'UsersFavorite.user_id'     => $this->Auth->user('id'),
2898                    'UsersFavorite.teacher_id'     => $teacherId,
2899                )
2900            ));
2901
2902            if ($favCount){
2903                $response = json_encode(array('res' => true, 'favCount' => $favCount, 'isFav' => $isFav));
2904            }
2905        }
2906        return $response;
2907    }
2908
2909    /**
2910     * @api {post} /user/waiting/getAlbum getAlbum()
2911     * @apiName getAlbum
2912     * @apiGroup Waiting
2913     * @apiDescription Retrieves the album of images for a specific teacher in Native Camp. It returns the list of approved images for the teacher.
2914     *
2915     * @apiBody {String} teacherId The ID of the teacher.
2916     * 
2917     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2918     * @apiSuccess {Object[]} [albums] The list of albums (only if the request was successful).
2919     * @apiSuccess {Number} albums.id The ID of the teacher image.
2920     * @apiSuccess {Number} albums.teacher_id The ID of the teacher.
2921     * @apiSuccess {Number} albums.approve_flg The approval flag of the image.
2922     * @apiSuccess {Number} albums.is_profile Indicates if the image is a profile image.
2923     * @apiSuccess {Number} albums.approve_required Indicates if the image requires approval.
2924     * @apiSuccess {String} albums.url The URL of the image.
2925     *
2926     * @apiSuccessExample {json} Success-Response:
2927     *     {
2928     *         "res": true,
2929     *         "albums": [
2930     *             {
2931     *                 "id": 1,
2932     *                 "teacher_id": 123,
2933     *                 "approve_flg": 1,
2934     *                 "is_profile": 0,
2935     *                 "approve_required": 0,
2936     *                 "url": "http://example.com/image.jpg"
2937     *             }
2938     *         ]
2939     *     }
2940     *
2941     * @apiError {Boolean} res Indicates whether the request was successful.
2942     *
2943     * @apiErrorExample {json} Error-Response:
2944     *     {
2945     *         "res": false
2946     *     }
2947     * 
2948     * @apiSampleRequest off
2949     */
2950    public function getAlbum() {
2951        $this->autoRender = false;
2952        $this->layout = false;
2953        $response = json_encode(array('res' => false)); // default
2954
2955        if($this->request->is('post')) {
2956            $post = $this->request->data;
2957            if (!isset($post['teacherId']) && $post['teacherId']) {
2958                return json_encode($response);
2959            }
2960            $teacherId = $post['teacherId'];
2961
2962            $this->TeacherImage->openDBReplica();
2963            $album = $this->TeacherImage->find('all', array(
2964                'fields' => array(
2965                    'TeacherImage.id',
2966                    'TeacherImage.teacher_id',
2967                    'TeacherImage.approve_flg',
2968                    'TeacherImage.is_profile',
2969                    'TeacherImage.approve_required',
2970                    'FileStorage.url'
2971                ),
2972                'conditions' => array(
2973                    'TeacherImage.teacher_id' => $teacherId,
2974                    'TeacherImage.is_profile' => 0,
2975                    'OR' => array(
2976                        'OR' => array(
2977                            'TeacherImage.approve_flg' => 1,
2978                            'TeacherImage.approve_required' => 0,
2979                        )
2980                    )
2981                ),
2982                'joins' => array(
2983                    array(
2984                        'type' => 'INNER',
2985                        'table' => 'file_storage',
2986                        'alias' => 'FileStorage',
2987                        'conditions' => array(
2988                            'TeacherImage.file_storage_id = FileStorage.id',
2989                            'FileStorage.uploader_type = 3',
2990                            'FileStorage.uploader_id' => $teacherId
2991                        )
2992                    )
2993                ),
2994                'order' => array('TeacherImage.id DESC')
2995            ));
2996            $this->TeacherImage->closeDBReplica();
2997
2998            if ($album){
2999                $response = json_encode(array('res' => true, 'albums' => $album));
3000            }
3001        }
3002        return $response;
3003    }
3004    
3005
3006    // NJ-3786 - arrange teacher data
3007    private function arrangeTeacherRecommendList( $params = array() ){
3008        $result = array();
3009        $data = isset( $params['data'] ) && $params['data'] ? $params['data'] : null;
3010        $userId = isset( $params['user_id'] ) && $params['user_id'] ? $params['user_id'] : null;
3011        $userData = isset($params['user_data']) && $params['user_data'] ?  $params['user_data'] : null;
3012        $nativeLanguage = isset($userData['native_language2']) && $userData['native_language2'] ?  $userData['native_language2'] : null;
3013        $platformArrangeApiList = (isset($params['platform_arrange']) && $params['platform_arrange'] == 'api') ;
3014        $categoryId = isset($params['category_id']) && $params['category_id'] ?  $params['category_id'] : null;
3015        $classStatusArr = Configure::read('teacher_lamp_color_class');
3016        $textbookImagUrl = null;
3017        if($categoryId){
3018            // Fetch textbook image
3019            $textbookParams = array(
3020                'conditions' => array('TextbookCategory.id' => $categoryId ),
3021                'fields' => array('TextbookCategory.image_big_url'),
3022                'recursive' => -1
3023            );
3024            ClassRegistry::init('TextbookCategory')->openDBReplica();
3025            $fetchTextbookData = ClassRegistry::init('TextbookCategory')->find('first',$textbookParams);
3026            ClassRegistry::init('TextbookCategory')->closeDBReplica();
3027            if($fetchTextbookData && isset($fetchTextbookData['TextbookCategory']['image_big_url']) && $fetchTextbookData['TextbookCategory']['image_big_url'] ){
3028                $textbookImagUrl = $fetchTextbookData['TextbookCategory']['image_big_url'];
3029            }
3030        }
3031
3032        if($data){
3033            foreach( $data as $index => $val ) {
3034                $teacherDetail = new TeacherTable($val['Teacher']);
3035                // - get countries
3036                $countries = strtolower($val['CountryCode']['country_name']);
3037                $explodeCountries = explode(' ', $countries);
3038                $implode = implode('_',$explodeCountries);
3039
3040                // - country name
3041                $countryName = $val['CountryCodeDetails']['country_name'] ? $val['CountryCodeDetails']['country_name'] : $val['CountryCode']['country_name'];
3042
3043                // - get residency
3044                $recidency = strtolower($countryName);
3045                $explodeRecidency = explode(' ', $recidency);
3046                $implodeResidency = implode('_',$explodeRecidency);
3047
3048                // - nationality
3049                $arrNationalityInfo = array(
3050                    "id" => "",
3051                    "name" => $val['CountryCode']['country_name'],
3052                    "flag" => $implode
3053                );
3054
3055                // - residence info
3056                $arrResidenceInfo = array(
3057                    "id" => "",
3058                    "name" => $countryName,
3059                    "flag" => $implodeResidency
3060                );
3061
3062                $getUserSettingLanguage = $nativeLanguage && $nativeLanguage == 'ja' ? $teacherDetail->jp_name : $teacherDetail->name ;
3063
3064                if( $platformArrangeApiList ) {
3065                    $result[$index] = array(
3066                        "id" => $teacherDetail->id,
3067                        "name" => $getUserSettingLanguage,
3068                        "name_ja" => $teacherDetail->jp_name,
3069                        "name_eng" => $teacherDetail->name,
3070                        "rating" => isset($val['TeacherTextbookWeeklyRating']['ratings']) ? number_format((float)$val['TeacherTextbookWeeklyRating']['ratings'], 2, '.', '') : 0,
3071                        "lessons" => isset($val['TeacherTextbookStat']['lesson_count']) ? $val['TeacherTextbookStat']['lesson_count'] : 0,
3072                        "favorite_count" => $this->UsersFavorite->getFavoriteCount($teacherDetail->id),
3073                        "age" => isset($val[0]['Teacher__age']) ? (int)$val[0]['Teacher__age'] : 0,
3074                        "nationality_id" =>(int)$val['CountryCode']['id'],
3075                        "image_main" =>  $teacherDetail->getImageUrl(),
3076                        // - country, residence info
3077                        'residence_image' =>  FULL_BASE_URL."/user/images/flag/".$arrResidenceInfo["flag"].".png",
3078                        'residence_name' => __d('default',$arrResidenceInfo["name"]),
3079                        'country_name' => __d('default',$arrNationalityInfo["name"]),
3080                        'country_image' =>  FULL_BASE_URL."/user/images/flag/".$arrNationalityInfo["flag"].".png",
3081                        'textbook_image_url' =>  $textbookImagUrl
3082                    );
3083                } else {
3084                    $result[$index]['Teacher'] = $val['Teacher'];
3085                    $result[$index]['Teacher']['lesson_count'] = isset($val['TeacherTextbookStat']['lesson_count']) ? $val['TeacherTextbookStat']['lesson_count'] : 0;
3086                    $result[$index]['Teacher']['favorite_count'] = $this->UsersFavorite->getFavoriteCount($teacherDetail->id);
3087                    $result[$index]['Teacher']['age'] = isset($val[0]['Teacher__age']) ? (int)$val[0]['Teacher__age'] : 0;
3088                    $result[$index]['Teacher']['evaluation_average'] = isset($val['TeacherTextbookWeeklyRating']['ratings']) ? number_format((float)$val['TeacherTextbookWeeklyRating']['ratings'], 2, '.', '') : __d('waiting', '集計中');
3089                    $result[$index]['Teacher']['image_url'] = $teacherDetail->getImageUrl();
3090                    $result[$index]['Teacher']['residence_image'] = FULL_BASE_URL."/user/images/flag/".$arrResidenceInfo["flag"].".png";
3091                    $result[$index]['Teacher']['residence_name'] = __d('default',$arrResidenceInfo["name"]);
3092                    $result[$index]['Teacher']['country_name'] = __d('default',$arrNationalityInfo["name"]);
3093                    $result[$index]['Teacher']['country_image'] = FULL_BASE_URL."/user/images/flag/".$arrNationalityInfo["flag"].".png";
3094                    $result[$index]['Teacher']['textbook_image_url'] = $textbookImagUrl;
3095                }
3096            }
3097        }
3098
3099        return $result;
3100
3101    }
3102
3103    //not sued function
3104    public function checkReservation($teacher, $onair_status) {
3105
3106        // 定数 取得 (category=26)
3107        $getDefineMaster = $this->DefineMaster->getDefine('26');
3108        // 入室できる時間(n分前)
3109        $DefinePossible = new DefineMasterTable($getDefineMaster[0]["DefineMaster"]);
3110        // レッスンできる時間(n分前)
3111        $DefineLessonPossible = new DefineMasterTable($getDefineMaster[0]["DefineMaster"]);
3112        $reserver = 0;
3113
3114        $floored_seconds = floor(time() / (30 * 60)) * (30 * 60);
3115        $ceiled_seconds = ceil(time() / (30 * 60)) * (30 * 60);
3116        // 予約状況を取得
3117        $this->LessonSchedule->recursive = -1;
3118        $getLessonSchedule = $this->LessonSchedule->getLessonSchedule(date('Y-m-d H:i:s', $floored_seconds), date('Y-m-d H:i:s', $ceiled_seconds), $teacher->id, 'asc');
3119
3120        // 予約がある
3121        if(!empty($getLessonSchedule)) {
3122            $LessonSchedule = new LessonScheduleTable($getLessonSchedule[0]["LessonSchedule"]);
3123
3124            // 入室できる時間
3125            $possible_time = strtotime("- " . $DefinePossible->contents . " minutes", strtotime($LessonSchedule->lesson_time));
3126
3127            // 予約時間
3128            $reservation_time = strtotime($LessonSchedule->lesson_time);
3129
3130            // レッスン可能な時間($lesson_possible_timeまで)
3131            $lesson_possible_time = strtotime("- " . $DefineLessonPossible->contents . " minutes", strtotime($LessonSchedule->lesson_time));
3132
3133            // 予約しているユーザのID
3134            $userID = $getLessonSchedule[0]['LessonSchedule']["user_id"];  //not used user id . undefined variable $getLessonSchedule
3135
3136            // 予約があっても 定数(category=26, sub_category=1)分前なら入室できる
3137            if(time() <= $possible_time && $onair_status == 1) {
3138                // 予約時間
3139                $this->set('ReservationTime', date('H:i', $reservation_time));
3140                // レッスン可能時間
3141                $this->set('PossibleTime',  date('H:i', $lesson_possible_time));
3142            }
3143
3144            # get minute now
3145            $minuteNow = (int) date("i");
3146
3147            // 予約してる人は自分
3148            if (
3149                $userID == $this->Auth->user('id') &&
3150                $onair_status == 2 &&
3151                !(
3152                    ($minuteNow >= 56 && $minuteNow <= 59) ||
3153                    ($minuteNow >= 26 && $minuteNow <= 29)
3154                )
3155            ) {
3156                $reserver = 1;
3157            }
3158        }
3159
3160        $this->set('isReserved', $reserver);
3161    }
3162
3163    /**
3164     * @api {get} /user/waiting/start/:teacher_id/:free_flg/:class_id/:chapter_id/:textbook_type start()
3165     * @apiName start
3166     * @apiGroup Waiting
3167     * @apiDescription Starts a lesson for a specific teacher and user in Native Camp. It checks various conditions and redirects to the appropriate page.
3168     *
3169     * @apiParam {String} teacher_id The ID of the teacher.
3170     * @apiParam {String} [free_flg=null] The free flag.
3171     * @apiParam {String} [class_id=1] The ID of the class.
3172     * @apiParam {String} [chapter_id=1] The ID of the chapter.
3173     * @apiParam {String} [textbook_type=null] The type of the textbook.
3174     * 
3175     * @apiSuccess {String} redirect_url The URL to which the user is redirected.
3176     *
3177     * @apiSuccessExample {json} Success-Response:
3178     *     {
3179     *         "redirect_url": "/class/index/123/1/1/1/1"
3180     *     }
3181     *
3182     * @apiError {String} status The status of the request (NG).
3183     * @apiError {String} message The error message.
3184     *
3185     * @apiErrorExample {json} Error-Response:
3186     *     {
3187     *         "status": "NG",
3188     *         "message": "Invalid request."
3189     *     }
3190     * 
3191     * @apiSampleRequest off
3192     */
3193    public function start($teacher_id, $free_flg=null, $class_id = null, $chapter_id = null, $textbook_type = null) {
3194        $this->autoRender = false;
3195        App::uses('myTools','Lib');
3196
3197        if (!$class_id)   $class_id     = 1;
3198        if (!$chapter_id) $chapter_id = 1;
3199
3200        if (is_null($teacher_id)) {
3201            return $this->redirect('/waiting/');
3202        }
3203        $data = $this->Teacher->findById($teacher_id);
3204        if (!$data) {
3205            return $this->redirect('/waiting/');
3206        }
3207
3208        /*
3209        * added in issue NC-488
3210        * check whether the user has been blocked already or not
3211        */
3212        //NJ-65055: params for checking teacher is hidden
3213        $isTeacherHiddenParams = array(
3214            'user_id' => $this->Auth->user('id'),
3215            'teacher_id' => $teacher_id
3216        );
3217
3218        if ((BlockListTable::isUserBlocked($this->Auth->User('id'), $teacher_id) == true) || $this->BlockList->isTeacherHide($isTeacherHiddenParams)) {
3219            return $this->redirect('/waiting/'); exit;
3220        }
3221
3222        // onairデータの中の講師IDがない
3223        $onAir = $this->LessonOnair->findByTeacherId($teacher_id);
3224        if (!isset($onAir['LessonOnair'])) {
3225            return $this->redirect('/');
3226        }
3227
3228        // レッスン中の場合
3229        if (!empty($onAir['LessonOnair']['status']) && $onAir['LessonOnair']['status']==3) {
3230            return $this->redirect('/waiting/detail/' . $teacher_id);
3231        }
3232
3233        // Overlapping reservation bug
3234        $lesson_available = $this->LessonSchedule->checkLessonAvailable($this->Auth->user('id'), $teacher_id);
3235        if (!$lesson_available) {
3236            return $this->redirect('/waiting/detail/' . $teacher_id);
3237        }
3238
3239
3240        $onAirId = $onAir['LessonOnair']['id'];
3241
3242        $this->Session->write('proceedFlag.clicked', 'true');
3243        return $this->redirect('/class/index/' . $teacher_id . '/' . $free_flg . '/' . $class_id . '/' . $chapter_id . '/' . $textbook_type);
3244    }
3245
3246    /**
3247     * @api {post} /user/waiting/teacherReserveList teacherReserveList()
3248     * @apiName teacherReserveList
3249     * @apiGroup Waiting
3250     * @apiDescription Retrieves the reservation list for a specific teacher in Native Camp. It returns various information about the available reservation slots, user eligibility, and more.
3251     *
3252     * @apiBody {String} teacherId The ID of the teacher.
3253     * @apiBody {Boolean} [counselingFlg=0] Indicates if the request is for counseling.
3254     * @apiBody {String} [hash16] The hash16 value for the user.
3255     * @apiBody {Number} [timeDiff=0] The time difference in seconds.
3256     * @apiBody {Boolean} [reservationHideFlg=false] Indicates if the reservation slots should be hidden.
3257     * @apiBody {Boolean} [hideLimitedPlanReservation=null] Indicates if the limited plan reservations should be hidden.
3258     * @apiBody {Number} [teacherCoin=0] The coin value for the teacher.
3259     * @apiBody {Number} [sapuriCoin=0] The coin value for Sapuri.
3260     * 
3261     * @apiSuccess {Object[]} days The list of days for the reservation slots.
3262     * @apiSuccess {String} days.Y The year.
3263     * @apiSuccess {String} days.m The month.
3264     * @apiSuccess {String} days.d The day.
3265     * @apiSuccess {String} days.w The day of the week.
3266     * @apiSuccess {String} days.reserve_range The reservation range for the day.
3267     * @apiSuccess {Boolean} days.canUseCoupon Indicates if a coupon can be used for the reservation.
3268     * @apiSuccess {Object[]} times The list of times for the reservation slots.
3269     * @apiSuccess {Object} reserved The reserved slots.
3270     * @apiSuccess {String} user_id The ID of the user.
3271     * @apiSuccess {Number} userCardCompany The card company of the user.
3272     * @apiSuccess {Number} timeDiff The time difference in seconds.
3273     * @apiSuccess {Object} reservedTz The reserved slots with timezone adjustments.
3274     * @apiSuccess {Boolean} limitedPlanAvailable Indicates if the limited plan reservation is available.
3275     * @apiSuccess {Boolean} hideLimitedPlanReservation Indicates if the limited plan reservations should be hidden.
3276     * @apiSuccess {Boolean} notCorporateLightTeachers Indicates if the teacher is not a corporate light teacher.
3277     * @apiSuccess {Boolean} corporateLightUser Indicates if the user is a corporate light user.
3278     * @apiSuccess {Boolean} corporateLimitedUser Indicates if the user is a corporate limited user.
3279     * @apiSuccess {Object} teacherInfo The information of the teacher.
3280     * @apiSuccess {Object} campaignPeriod The campaign period information.
3281     * @apiSuccess {Object} discountCampaignPeriod The discount campaign period information.
3282     * @apiSuccess {String} currentUserTime The current user time.
3283     * @apiSuccess {String} currentUtcOffset The current UTC offset.
3284     * @apiSuccess {Boolean} isShowCancellationAlert Indicates if the cancellation alert should be shown.
3285     * @apiSuccess {Object[]} otherReservations The list of other reservations.
3286     * @apiSuccess {Boolean} viewSlotForSapuri Indicates if the slot is for Sapuri.
3287     * @apiSuccess {String} studySapuriId The ID of the study Sapuri.
3288     * @apiSuccess {Object[]} lessonRequestSlot The list of lesson request slots.
3289     * @apiSuccess {Boolean} lessonRequestInvalidPlan Indicates if the lesson request plan is invalid.
3290     * @apiSuccess {String} teacherId The ID of the teacher.
3291     * @apiSuccess {Number} callanOption Indicates if the Callan option is available.
3292     * @apiSuccess {Object} user The user information.
3293     * @apiSuccess {Object} teacherData The teacher data.
3294     * @apiSuccess {String[]} weekday The list of weekdays.
3295     * @apiSuccess {Object} hiddenReservedTz The hidden reserved slots with timezone adjustments.
3296     * @apiSuccess {Boolean} canLive Indicates if the user can join live lessons.
3297     * @apiSuccess {Boolean} normalLitePlanCanReserveFlg Indicates if the normal lite plan can reserve.
3298     * @apiSuccess {Boolean} isNormalLitePlan Indicates if the user is on a normal lite plan.
3299     * @apiSuccess {Boolean} notNormalLitePlanTeacher Indicates if the teacher is not a normal lite plan teacher.
3300     * @apiSuccess {Boolean} teacherCoinDisableSlots Indicates if the teacher coin disables slots.
3301     * @apiSuccess {Boolean} excludeLessonRequestDiscount Indicates if the lesson request discount should be excluded.
3302     * @apiSuccess {Number} lessonRequestFlg The lesson request flag.
3303     * @apiSuccess {Boolean} notNewCampaignEligible Indicates if the user is not eligible for the new campaign.
3304     * @apiSuccess {String} teacherImageSrc The image URL of the teacher.
3305     * @apiSuccess {String} teacherName The name of the teacher.
3306     *
3307     * @apiSuccessExample {json} Success-Response:
3308     *     {
3309     *         "days": [
3310     *             {
3311     *                 "Y": "2023",
3312     *                 "m": "12",
3313     *                 "d": "01",
3314     *                 "w": "(金)",
3315     *                 "reserve_range": "10:00~11:00",
3316     *                 "canUseCoupon": true
3317     *             }
3318     *         ],
3319     *         "times": ["10:00", "10:30", "11:00"],
3320     *         "reserved": {...},
3321     *         "user_id": "123",
3322     *         "userCardCompany": 1,
3323     *         "timeDiff": 0,
3324     *         "reservedTz": {...},
3325     *         "limitedPlanAvailable": true,
3326     *         "hideLimitedPlanReservation": false,
3327     *         "notCorporateLightTeachers": false,
3328     *         "corporateLightUser": true,
3329     *         "corporateLimitedUser": false,
3330     *         "teacherInfo": {...},
3331     *         "campaignPeriod": {...},
3332     *         "discountCampaignPeriod": {...},
3333     *         "currentUserTime": "2023/12/01 10:00",
3334     *         "currentUtcOffset": "+09:00",
3335     *         "isShowCancellationAlert": true,
3336     *         "otherReservations": [...],
3337     *         "viewSlotForSapuri": true,
3338     *         "studySapuriId": "sapuri123",
3339     *         "lessonRequestSlot": [...],
3340     *         "lessonRequestInvalidPlan": false,
3341     *         "teacherId": "456",
3342     *         "callanOption": 1,
3343     *         "user": {...},
3344     *         "teacherData": {...},
3345     *         "weekday": ["(日)", "(月)", "(火)", "(水)", "(木)", "(金)", "(土)"],
3346     *         "hiddenReservedTz": {...},
3347     *         "canLive": true,
3348     *         "normalLitePlanCanReserveFlg": true,
3349     *         "isNormalLitePlan": true,
3350     *         "notNormalLitePlanTeacher": false,
3351     *         "teacherCoinDisableSlots": false,
3352     *         "excludeLessonRequestDiscount": false,
3353     *         "lessonRequestFlg": 1,
3354     *         "notNewCampaignEligible": false,
3355     *         "teacherImageSrc": "http://example.com/image.jpg",
3356     *         "teacherName": "John Doe"
3357     *     }
3358     *
3359     * @apiError {String} status The status of the request (NG).
3360     * @apiError {String} message The error message.
3361     *
3362     * @apiErrorExample {json} Error-Response:
3363     *     {
3364     *         "status": "NG",
3365     *         "message": "Invalid request."
3366     *     }
3367     * 
3368     * @apiSampleRequest off
3369     */
3370    public function teacherReserveList() {
3371        $this->layout = "";
3372
3373        if (!$this->request->is('post')) {
3374            return ;
3375        }
3376
3377        $data = $this->request->data;
3378        $teacherId = isset($data['teacherId']) ? $data['teacherId'] : null;
3379        $counselingFlg = isset($data['counselingFlg']) ? $data['counselingFlg'] : 0;
3380        $hash16 = isset($data['hash16']) ? $data['hash16'] : null;
3381        $timeDiff = isset($data['timeDiff']) ? $data['timeDiff'] : 0;
3382        $reservationHideFlg = isset($data['reservationHideFlg']) ? $data['reservationHideFlg'] : false;
3383        $hideLimitedPlanReservation = isset($data['hideLimitedPlanReservation']) ? $data['hideLimitedPlanReservation'] : null;
3384        $teacherCoin = isset($data['teacherCoin']) ? $data['teacherCoin'] : 0;
3385        $sapuriCoin = isset($data['sapuriCoin']) ? $data['sapuriCoin'] : 0;
3386        $viewSlotForSapuri = false;
3387
3388        if (empty($teacherId)) {
3389            return ;
3390        }
3391
3392        $userId = $this->Auth->user('id');
3393        $teacher = ClassRegistry::init('Teacher')->getTeacherInfo($teacherId);
3394        $teacherInfo = $teacher['Teacher'];
3395        $userLanguage =  !empty($this->Auth->user('native_language2')) ? $this->Auth->user('native_language2') :Configure::read('default.user_language');
3396
3397        $this->User->recursive = -1;
3398        $user = $this->User->findById($userId);
3399
3400        // NJ-18780 : set var if callan half price teacher 
3401        $_isCallanHalfTeacher = (int) $teacherInfo['callan_halfprice_flg'];
3402
3403        if (
3404            $this->sharedUserData && 
3405            $this->isStudySapuriUser && 
3406            $sapuriCoin && 
3407            $teacherCoin <= $sapuriCoin
3408        ) {
3409            $viewSlotForSapuri = true;
3410            $userObj = new UserTable($this->sharedUserData['User']);
3411            $plan = $userObj->isStudySapuri();
3412            
3413            //NJ-10847 Hide Slots if Teacher has no Sapuri Textbook Badge
3414            $badgeParams = array('plan' => $plan, 'teacher_id' => $teacherId);
3415            $badges = TeacherBadgeTable::getSapuriStudentAndTeacherBadge($badgeParams);
3416            if (!$badges) {
3417                $viewSlotForSapuri = false;
3418            }
3419        }
3420
3421        // Hide reservations slot if lite plan and reservation coin is 0 
3422        if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && $teacherCoin <= 0) {
3423            $reservationHideFlg = true;
3424        }
3425
3426        $isCorporateUser = isset($this->sharedUserData['User']) && !empty($this->sharedUserData['User']['corporate_id']);
3427        $forceFetchCampaignPeriod = $isCorporateUser || $this->isStudySapuriUser;
3428
3429        $times = array();
3430        $utcMin = explode(':', $this->utcOffset);
3431        if ($utcMin[1] == "45") {
3432            for ($i=0; $i<=23; $i++) {
3433                $times[] = sprintf("%02d",$i) . ':15';
3434                $times[] = sprintf("%02d",$i) . ':45';
3435            }
3436        } else {
3437            for ($i=0; $i<=23; $i++) {
3438                $times[] = sprintf("%02d",$i) . ':00';
3439                $times[] = sprintf("%02d",$i) . ':30';
3440            }
3441        }
3442
3443        $days = array();
3444
3445        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { // if the language is Custom language format
3446            $weekday = array( __dx('waiting', 'day_three_letter', '(日)'), __dx('waiting', 'day_three_letter','(月)'), __dx('waiting', 'day_three_letter','(火)'), __dx('waiting', 'day_three_letter','(水)'), __dx('waiting', 'day_three_letter','(木)'), __dx('waiting', 'day_three_letter','(金)'), __dx('waiting', 'day_three_letter','(土)') );
3447        } else { // if the language is not Custom language format
3448            $weekday = array( __d('waiting','(日)'), __d('waiting','(月)'), __d('waiting','(火)'), __d('waiting','(水)'), __d('waiting','(木)'), __d('waiting','(金)'), __d('waiting','(土)') );
3449        }
3450
3451        $reserved = array();
3452        // if reservation_hide_flg, display open reservation slots
3453        
3454        // 予約状況を取得
3455        // ~ hide slots if teacher reservation hide flg is true
3456        if (!$reservationHideFlg) {
3457            $reserved = $this->LessonSchedule->findReserveListByTeacherIdAndLessondate(
3458                $userId,
3459                $teacherId,
3460                date('Ymd', time()),
3461                date('Ymd', strtotime("+8 days", time())),
3462                false,
3463                $reservationHideFlg
3464            );
3465        }
3466
3467        // // overide reserved for campaign hide slots for not eligeble users
3468        // if ($reservationCampaignHideFlg && isset($campaignDiscountFlg) && $campaignDiscountFlg) {
3469        //     $reserved = $this->LessonSchedule->findReserveListByTeacherIdAndLessondate(
3470        //         $userId,
3471        //         $teacherId,
3472        //         date('Ymd', strtotime($campaignDiscountFlg['CampaignInstructor']['start_date'])),
3473        //         date('Ymd', strtotime($campaignDiscountFlg['CampaignInstructor']['end_date'])),
3474        //         false,
3475        //         $reservationCampaignHideFlg
3476        //     );
3477        // }
3478        
3479        // if have own reserved or available slot, check for live lesson slot
3480        $liveShift = array();
3481        $liveShiftLessonTimeData = [];
3482        if ($reserved) {
3483            $this->ShiftWorkOn->openDBReplica();
3484            $liveShift = $this->ShiftWorkOn->find('all', array(
3485                'fields' => ['ShiftWorkOn.lesson_time','DATE_FORMAT(ShiftWorkOn.lesson_time, \'%Y%m%d%H%i%S\') AS time'],
3486                'conditions' => array(
3487                    'ShiftWorkOn.teacher_id' => $teacherId,
3488                    'ShiftWorkOn.live_lesson_flg' => 1,
3489                    'ShiftWorkOn.hide_flg' => 0,
3490                    'ShiftWorkOn.lesson_time >= NOW()'
3491                ),
3492                'recursive' => -1
3493            ));
3494            $this->ShiftWorkOn->closeDBReplica();
3495
3496            $canLive = true;
3497            if ($liveShift) {
3498                if ($this->sharedUserData) {
3499                    $canLive = UserTable::canDoLiveViewing($this->sharedUserData['User']);
3500                }
3501                foreach ($liveShift as $shift) {
3502
3503                    if( isset($shift['ShiftWorkOn']['lesson_time']) && $shift['ShiftWorkOn']['lesson_time'] ) {
3504                        $liveShiftLessonTimeData[] = $shift['ShiftWorkOn']['lesson_time'];
3505                    }
3506
3507                    if ( empty($reserved[$shift[0]['time']]) ) {
3508                        continue;
3509                    }
3510
3511                    //-- open for live lesson resevation
3512                    if ( $reserved[$shift[0]['time']] == 9 ) {
3513                        if (!$canLive) {
3514                            unset($reserved[$shift[0]['time']]);     //-- hide live lesson for invalid member
3515                        } else {
3516                            $reserved[$shift[0]['time']] = 10;         //-- available live
3517                        }
3518
3519                    //-- own live lesson reservation
3520                    } elseif ( $reserved[$shift[0]['time']] == 2 ) {
3521                        $reserved[$shift[0]['time']] = 11;
3522
3523                    //-- other student live lesson reservation
3524                    } elseif ( $reserved[$shift[0]['time']] == 1 ) {
3525                        if (!$canLive) {
3526                            unset($reserved[$shift[0]['time']]);     //-- hide live lesson for invalid member
3527                        } else {
3528                            $reserved[$shift[0]['time']] = 12;         //-- reserved by another
3529                        }
3530                    }
3531                }
3532            }
3533        }
3534
3535        // Check if sapuri user and with in campaign's duration (sicth anniv, christmas)
3536        $ifSapuriAndCampaign = false;
3537        $sixthAnnivCampaignDateArr = Configure::read('campaign_config.sixth_anniv_1.period');
3538        // $christmasDateArr = Configure::read('campaign_config.christmas.period');
3539        // $goldenWeekDateArr = Configure::read('campaign_config.christmas.period');
3540        if (
3541            (
3542                (time() >= strtotime($sixthAnnivCampaignDateArr['start']) && time() <= strtotime($sixthAnnivCampaignDateArr['end']))
3543                // || (time() >= strtotime($christmasDateArr['start']) && time() <= strtotime($christmasDateArr['end']))
3544                // || (time() >= strtotime($goldenWeekDateArr['start']) && time() <= strtotime($goldenWeekDateArr['end']))
3545            )
3546            && $this->studySapuriId
3547        ) {
3548            $ifSapuriAndCampaign = true;
3549        }
3550        $isCorporateUser = isset($this->sharedUserData['User']) && !empty($this->sharedUserData['User']['corporate_id']);
3551        $forceFetchCampaignPeriod = $isCorporateUser || $this->isStudySapuriUser;
3552
3553        //campaign period start and end time
3554        $campaignPeriod = null;
3555        if (($reserved && !$ifSapuriAndCampaign) || $forceFetchCampaignPeriod) {
3556            $campaignPeriod = $this->PopularTeacherCampaignPeriod->fetchCampaignPeriod(array(
3557                'user_id' => $this->Auth->user('id'),
3558                'teacher_id' => $teacherId,
3559                'bypass_count' => $forceFetchCampaignPeriod
3560            ));
3561        }
3562
3563        if (($reserved && !$ifSapuriAndCampaign) || $forceFetchCampaignPeriod) {
3564            $discountcampaignPeriod = $this->CampaignInstructor->fetchNewCampaignPeriod(array(
3565                'user_id' => $this->Auth->user('id'),
3566                'teacher_id' => $teacherId,
3567                'bypass_count' => $forceFetchCampaignPeriod
3568            ));
3569        }
3570
3571        //NJ-28004 get current reservation
3572        $currentReseervations = $this->LessonSchedule->getCurrentTeacherReservation($teacherId, $userId);
3573
3574        //NC-3787 - get all users reservation except for current teacher
3575        $otherReservations = $this->LessonSchedule->getOtherReservationsExcept($teacherId, $userId);
3576        $reservedDate = '';
3577        $reservedTz = array();
3578        $teacherData = array();
3579        $reservedArr = is_array($reserved) ? $reserved : [];
3580
3581        $allLessonTimes = array_unique(array_merge(
3582            array_map(function($reservedData) {
3583                return date('Y-m-d H:i:s', strtotime($reservedData));
3584            }, array_keys($reservedArr)),
3585            $otherReservations,
3586            $currentReseervations
3587        ));
3588
3589        $allLessonTimes = is_array($allLessonTimes) ? $allLessonTimes : [];
3590        $lessonTimesParams = array(
3591            'lesson_times' => $allLessonTimes,
3592            'teacher_id' => $teacherId,
3593            'user_id' => $userId,
3594            'localize_dir' => $this->localizeDir,
3595            'campaign' => $discountcampaignPeriod
3596        );
3597
3598        $allReservationsData = $this->LessonSchedule->getAllReservationData($lessonTimesParams);
3599
3600        if (is_iterable($reserved)) {
3601            foreach($reserved as $key => $val) {
3602
3603                $teacherSlotEvent = Configure::read('reservation_event_type.normal');
3604                $reservedLessonTime = date('Y-m-d H:i:s', strtotime($key));
3605                $campaignPeriod['lesson_time'] = $reservedLessonTime;
3606                $discountcampaignPeriod['lesson_time'] = $reservedLessonTime;
3607                $inCampaign = false;
3608                $inNewCampaign = false;
3609
3610                if ($this->CampaignInstructor->checkCampaignPeriod($discountcampaignPeriod)) {
3611                    $inNewCampaign = true;
3612                }
3613
3614                if ($this->CampaignInstructor->checkCampaignPeriod($discountcampaignPeriod)) {
3615                    $inNewCampaign = true;
3616                }
3617
3618                if( $liveShiftLessonTimeData && in_array($reservedLessonTime,$liveShiftLessonTimeData) ) {
3619                    $teacherSlotEvent = Configure::read('reservation_event_type.live_lesson');
3620                } elseif( $inCampaign ) {
3621                    $teacherSlotEvent = Configure::read('reservation_event_type.popular_campaign');
3622                }elseif( $inNewCampaign ) {
3623                    $teacherSlotEvent = Configure::read('reservation_event_type.discount_campaign');
3624                }
3625
3626                $teacherData = in_array($reservedLessonTime, $otherReservations) ? ($allReservationsData[$reservedLessonTime] ?? []) : [];
3627                $currentTeacherData = in_array($reservedLessonTime, $currentReseervations) ? ($allReservationsData[$reservedLessonTime] ?? []) : [];
3628
3629                $reservedDatas = [
3630                    'reserved' => $key,
3631                    'val' => $val,
3632                    'reservation_event' => $teacherSlotEvent,
3633                    'teacherData' => $teacherData,
3634                    'currentTeacherData' => $currentTeacherData
3635                ];
3636
3637                $timeKeySlot = TimezoneTable::computeTimeToUser(array('time' => strtotime($key), 'timestamp' => $this->timeDiffSecond, 'format' => 'YmdHis'));
3638                $reservedTz[$timeKeySlot] = $reservedDatas;
3639
3640                $currentDate = substr($key, 0,8);
3641                $min = date('i', strtotime($key));
3642                $hour = intval(date('H', strtotime($key)));
3643                if ($min == '30') {
3644                    $hour = $hour + 1;
3645                    $min = ":00";
3646                } else {
3647                    $min = ":30";
3648                }
3649                if ($reservedDate != $currentDate) {
3650                    if (!isset($reservedRange[$currentDate][0])) {
3651                        $reservedRange[$currentDate][0] = date('H:i', strtotime($key));
3652                        $reservedRange[$currentDate][1] = strval($hour).$min;
3653                    } else {
3654                        $reservedRange[$currentDate][1] = strval($hour).$min;
3655                    }
3656                } else {
3657                    $reservedRange[$currentDate][1] = strval($hour).$min;
3658                }
3659                $rKeys = array_keys($reservedRange);
3660                $rLastKey = end($rKeys);
3661                $reservedDate = $rLastKey;
3662
3663            }
3664        }
3665
3666        if (is_iterable($otherReservations)) {
3667            foreach($otherReservations as $key => $val) {
3668                $teacherSlotEvent = Configure::read('reservation_event_type.normal');
3669                $timeKeySlot = TimezoneTable::computeTimeToUser(array('time' => strtotime($val), 'timestamp' => $this->timeDiffSecond, 'format' => 'YmdHis'));
3670                $reservedLessonTime = date('Y-m-d H:i:s', strtotime($val));
3671
3672                // - do nothing - avoid conflict
3673                if (isset($reservedTz[$timeKeySlot])) {
3674                    continue;
3675                }
3676
3677                // - set reservation info
3678                $teacherData = $allReservationsData[$reservedLessonTime] ?? [];
3679                $currentTeacherData = $allReservationsData[$reservedLessonTime] ?? [];
3680
3681                // - set reservation data
3682                $reservedDatas = [
3683                    'reserved' => $val,
3684                    'val' => [],
3685                    'reservation_event' => $teacherSlotEvent,
3686                    'teacherData' => $teacherData,
3687                    'currentTeacherData' => $currentTeacherData
3688                ];
3689
3690                // - set reserved TZ
3691                $reservedTz[$timeKeySlot] = $reservedDatas;
3692            }
3693        }
3694
3695        $coupon = false;
3696        $couponDateCanUse = date('Y-m-d');
3697        $ccPeriod = false;
3698        if (!is_null($hash16)) {
3699            $freeTicket = false;
3700            if(PaymentTable::checkIfPaidUser($userId, $hash16)) {
3701                $freeTicket = true;
3702            } elseif (PaymentTable::checkIfCardAuth($userId, $hash16)) {
3703                $freeTicket = true;
3704            }
3705
3706            if ($freeTicket) {
3707                // check if can use coupon for reservation
3708                $coupon = ClassRegistry::init('UserCoupon')->canUseCoupon($userId);
3709                // get last coupon date used
3710                $couponDateCanUse = ClassRegistry::init('UserCoupon')->getDateCouponCanUse($userId);
3711
3712                // check if coupon campaign period
3713                $ccPeriod = myTools::couponCampaignPeriod();
3714            }
3715        }
3716        for ($i=0; $i<=7; $i++) {
3717            $cTime = strtotime("+" . $i . " days", $this->displayTime);
3718            $canUseCoupon = false;
3719            if (
3720                $couponDateCanUse && $coupon && $ccPeriod && !$counselingFlg
3721                && strtotime(date('Y-m-d', $cTime)) >= strtotime($couponDateCanUse)
3722            ) {
3723                $canUseCoupon = true;
3724            }
3725            $resRange = (isset($reservedRange[date('Ymd', $cTime)]))?$reservedRange[date('Ymd', $cTime)][0].'~'.$reservedRange[date('Ymd', $cTime)][1]:'';
3726            $days[] = array(
3727                'Y' => date('Y', $cTime),
3728                'm' => date('m', $cTime),
3729                'd' => date('d', $cTime),
3730                'w' => $weekday[date("w", $cTime)],
3731                'reserve_range' => $resRange,
3732                'canUseCoupon' => $canUseCoupon
3733            );
3734        }
3735
3736        // NC-4546 - check phone verification auth
3737        $verifyCount = $this->PhoneVerifyCheckLog->find('count',array(
3738            'conditions' => array(
3739                'user_id' => $this->Auth->User('id'),
3740                'status' => 0
3741            )
3742        ));
3743        $notCorporateLightTeachers = false;
3744        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id'] );
3745
3746        if ( isset($corporateType) && $corporateType == Configure::read("corporate_type.light") ) {
3747            $checkCorpLightTeacher = ClassRegistry::init('Teacher')->corporateLightTeacher($teacherId);
3748            if (!$checkCorpLightTeacher) {
3749                $notCorporateLightTeachers = true;
3750            }
3751        }
3752
3753
3754        $grc = $this->getReserveAndCancelled($teacherId);
3755        $isShowCancellationAlert = $grc['this_month_cancellation_rate'] >= Configure::read('alert_cancellation_rate') ? true : false;
3756
3757        $limitedPlanAvailable = false;
3758
3759        // if user is corporate limited check if limited plan reservation is ON
3760        if ($corporateType == Configure::read("corporate_type.limited")) {
3761            $this->TeacherRankCoin->openDBReplica();
3762            $teacherRankCoin = $this->TeacherRankCoin->find('first', array(
3763                'fields' => array('TeacherRankCoin.limited_plan_reservation'),
3764               'conditions' => array('TeacherRankCoin.id' => $teacher['Teacher']['rank_coin_id'])
3765            ));
3766            $this->TeacherRankCoin->closeDBReplica();
3767
3768            $teacherRankCoin = $teacherRankCoin ? $teacherRankCoin['TeacherRankCoin'] : false;
3769            $limitedPlanAvailable = $teacherRankCoin && $teacherRankCoin['limited_plan_reservation'];
3770        }
3771        
3772        $callan_unlimited_flg = 0;
3773
3774
3775        # NJ-19429: check if teacher is in campaign
3776        if(
3777            (isset($user['User']['callan_option']) && $user['User']['callan_option'])
3778            ||
3779            (isset($user['User']['native_option']) && $user['User']['native_option'])
3780        ) {
3781            // - check existing reservation
3782            $has_callan_option_reserved = $this->LessonSchedule->hasCallanOptionReserved($userId);
3783            
3784            if($has_callan_option_reserved == 0) {
3785                // - check teacher callan option
3786                $unlimited_option_flag = $this->HomeBasedRankBasicAmount->getUnlimitedOptionFlg($teacherInfo['current_rank_id']);
3787                $callan_unlimited_flg = (isset($unlimited_option_flag['callan_unlimited_option_flg']) && $unlimited_option_flag['callan_unlimited_option_flg']) ? 1 : 0;
3788            }
3789        }
3790        
3791        #NJ-18780:set to allow normal lite plan to reserve
3792        $normalLitePlanCanReserveFlg = true;
3793        $isNormalLitePlan = false;
3794        $notNormalLitePlanTeacher = false;
3795
3796        $lessonRequestSlot = array();
3797
3798        if($this->isStudySapuriTosUser) {
3799            $lessonRequestSlot = array();            
3800        } else if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && $teacherCoin <= 0) {
3801            $lessonRequestSlot = array();
3802        } else {
3803            //-- lesson request schedule
3804
3805            // - NJ-46366: prefetch lesson request slot
3806            $prefetchStart = date("Y-m-d 00:00:00");
3807            $prefetchEnd = date("Y-m-d 23:59:59", strtotime("+7 day"));
3808
3809            $prefetchedUserReservationData = $this->LessonSchedule->getReservationData(
3810                ['startDate' => $prefetchStart, 
3811                'endDate' => $prefetchEnd], 
3812                $user['User']['id'],
3813                $userLanguage
3814            );
3815    
3816            $prefetchedUsersCancelledReservationData = $this->LessonScheduleCancel->hasSlotBeenCancelled([
3817                'user_id' => $user['User']['id'],
3818                'lesson_time' => [
3819                    'startDate' => $prefetchStart, 
3820                    'endDate' => $prefetchEnd
3821                ]
3822            ]);
3823            
3824            $lessonRequestSlot = $this->LessonSchedule->lessonRequestSlotDetail(array(
3825                'user_id' => $userId,
3826                'teacher_id' => $teacherId,
3827                'timeDiffSecond' => $this->timeDiffSecond,
3828                'user_language' => $this->localizeDir,
3829                'campaign' => $discountcampaignPeriod,
3830                'userReservationData' => $prefetchedUserReservationData,
3831                'cancelledReservationData' => $prefetchedUsersCancelledReservationData
3832            ));
3833
3834            //-override hide dates or closed slots fetch reservation data
3835            $hiddenReservedTz = [];
3836            $resData = $this->LessonSchedule->getHiddenReservation([
3837                'user_id' => $userId
3838            ]);
3839
3840            if ($resData) {
3841                foreach ($resData as $key => $row) {
3842                    $lessonReqquestSlotData = $this->LessonSchedule->getReservationData($key, $userId, $this->localizeDir);
3843                    if (!empty($lessonReqquestSlotData)) {
3844                        $lessonReqquestSlotData['icon_color'] = $this->LessonSchedule->getIconColor($lessonReqquestSlotData, $key);
3845                        $hiddenReservedTz[TimezoneTable::computeTimeToUser(array('time' => strtotime($key), 'timestamp' => $this->timeDiffSecond, 'format' => 'YmdHis'))] = $lessonReqquestSlotData;
3846                    }
3847                }
3848            }
3849        }
3850
3851        $membershipStatusIndex = UserTable::getStudentMembershipStatus($this->Auth->User('id'));
3852        $CampaignEligible = $this->CampaignInstructor->verifyStudentMembership($this->Auth->User('id'));
3853        $isNotNewCampaignEligible = !$CampaignEligible['verified'];
3854
3855        // NJ-33414
3856        $this->UsersDetail->openDBReplica();
3857        $fetchUsersDetail = $this->UsersDetail->find('first', array(
3858            'fields' => array(
3859                'user_id',
3860                'lesson_request_flg'
3861            ),
3862            'conditions' =>  array('user_id' => $userId),
3863            'recursive' => -1
3864        ));
3865        $this->UsersDetail->closeDBReplica();
3866        // - check if light plan and over ride to allow reserve on live lesson
3867        if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans'))) {
3868            # not allow user to reserve live lesson
3869            $canLive = false;
3870        
3871            #set to normal lite plan user
3872            $isNormalLitePlan = true;
3873        
3874            #count the total upcoming reservation limited only to 1 reservation ?
3875            $liteUserReservationCount = $this->LessonSchedule->countUserTotalReservation(array('userId' => $userId));
3876        
3877            if ($liteUserReservationCount >= Configure::read("lite_plan_maximum_number_of_total_reservation")) {
3878                # not allow to reserve any more
3879                $normalLitePlanCanReserveFlg = false;
3880            }
3881
3882            // - check if teacher is callan half price
3883            if ($_isCallanHalfTeacher == 1 && empty($campaign)) {
3884                $notNormalLitePlanTeacher = true;
3885
3886                // - hide slots for lesson request 
3887                $lessonRequestSlot =  array();
3888            }
3889        }
3890
3891        //NJ-19429: teacher coin in slot restriction
3892        $teacherCoinDisableSlots = false;
3893        if($teacherCoin > 100){
3894            $isSlotReserveDisabled = in_array($membershipStatusIndex, Configure::read('slots_disabled_membership'));
3895            if($isSlotReserveDisabled){
3896                $lessonRequestSlot = array();
3897                $teacherCoinDisableSlots = true;
3898            }
3899        }
3900
3901        // NJ-47838 : check if live lesson callan discount campaign is enabled 
3902        $isLiveDiscountCallanCampaignCount = ClassRegistry::init('CampaignTagControl')->checkTeacherLiveCallanTag($discountcampaignPeriod['campaign_tag_id']);
3903        $excludeLessonRequestDiscount ??= '';
3904        $this->set(array(
3905            'smsThroughFlg' => isset($user['User']['sms_through_flg']) ? $user['User']['sms_through_flg'] : false,
3906            'verifyCount' => $verifyCount,
3907            'days' => $days,
3908            'times' => $times,
3909            'reserved' => $reserved,
3910            'user_id' => ($this->Auth->loggedIn()) ? $userId : null,
3911            'userCardCompany' => isset($user['User']['card_company']) ? $user['User']['card_company'] : 0,
3912            'timeDiff' => $timeDiff,
3913            'reservedTz' => $reservedTz,
3914            'limitedPlanAvailable' => $limitedPlanAvailable,
3915            'hideLimitedPlanReservation' => $hideLimitedPlanReservation,
3916            'notCorporateLightTeachers' => $notCorporateLightTeachers,
3917            'corporateLightUser' => ($corporateType == Configure::read("corporate_type.light")),
3918            'corporateLimitedUser' => ($corporateType == Configure::read("corporate_type.limited")),
3919            'teacherInfo' => $teacherInfo,
3920            'campaignPeriod' => $campaignPeriod,
3921            'discountCampaignPeriod' => $discountcampaignPeriod,
3922            'currentUserTime' => date(
3923                isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support")) ? 
3924                'd/m/Y G:i' : 'Y/m/d G:i', 
3925                $this->displayTime
3926            ),
3927            'currentUtcOffset' => $this->utcOffset,
3928            'isShowCancellationAlert' => $isShowCancellationAlert,
3929            'otherReservations' => $otherReservations,
3930            'viewSlotForSapuri' => $viewSlotForSapuri,
3931            'studySapuriId' => $this->studySapuriId,
3932            'lessonRequestSlot' => $lessonRequestSlot,
3933            'lessonRequestInvalidPlan' => in_array($membershipStatusIndex, [12, 13]),
3934            'teacherId' => $teacherId,
3935            'callanOption' => $callan_unlimited_flg,
3936            'user' => $user,
3937            'teacherData' => $teacherInfo,
3938            'weekday' => $weekday,
3939            'hiddenReservedTz' => $hiddenReservedTz,
3940            'canLive' => $canLive,
3941            'normalLitePlanCanReserveFlg' => $normalLitePlanCanReserveFlg,
3942            'isNormalLitePlan' => $isNormalLitePlan,
3943            'notNormalLitePlanTeacher' => $notNormalLitePlanTeacher,
3944            'teacherCoinDisableSlots' => $teacherCoinDisableSlots,
3945            'excludeLessonRequestDiscount'=> $excludeLessonRequestDiscount ? true : false,
3946            'lessonRequestFlg' => $fetchUsersDetail ? (int)$fetchUsersDetail['UsersDetail']['lesson_request_flg'] : 1,   // NJ-33414
3947            'notNewCampaignEligible' => $isNotNewCampaignEligible,
3948            'isLiveDiscountCallanCampaignCount' => $isLiveDiscountCallanCampaignCount
3949        ));
3950
3951        // get teacher information
3952        $teacher = new TeacherTable($teacherInfo);
3953        $teacherImageSrc = $teacher->getImageUrl();
3954        $teacherName = $teacher->getName();
3955        $this->set('teacherImageSrc', $teacherImageSrc);
3956        $this->set('teacherName', $teacherName);
3957
3958        $this->render('teacher_reserve_list_new');
3959
3960    }
3961
3962    //not used function
3963    public function updateChapterOptions() {
3964        $this->autoRender = false;
3965        $classId = $this->request->data['classid'];
3966        $teacherId = $this->request->data['teacherid'];
3967
3968        if (isset($this->request->data['firstid'])) {
3969            $firstId = $this->request->data['firstid'];
3970        } else {
3971            $firstId = '';
3972        }
3973
3974        if (isset($this->request->data['lastid'])) {
3975            $lastId = $this->request->data['lastid'];
3976        } else {
3977            $lastId = '';
3978        }
3979        return $this->result($teacherId, $classId, $firstId, $lastId);
3980    }
3981
3982    /**
3983     * @api {post} /user/waiting/result/:teacherId/:classId/:firstId/:lastId result()
3984     * @apiName result
3985     * @apiGroup Waiting
3986     * @apiDescription Retrieves the list of chapters for a specific class and teacher in Native Camp. It returns the updated list of chapters along with the first and last chapter IDs.
3987     *
3988     * @apiParam {String} teacherId The ID of the teacher.
3989     * @apiParam {String} classId The ID of the class.
3990     * @apiParam {String} [firstId] The ID of the first chapter.
3991     * @apiParam {String} [lastId] The ID of the last chapter.
3992     * 
3993     * @apiSuccess {Object[]} chapterList The list of chapters.
3994     * @apiSuccess {String} chapterList.UsersLastViewedTextbook.last_viewed_date The last viewed date of the chapter.
3995     * @apiSuccess {String} chapterList.LessonText.chapter_id The ID of the chapter.
3996     * @apiSuccess {String} chapterList.LessonText.chapter The name of the chapter.
3997     * @apiSuccess {String} firstChapter The ID of the first chapter.
3998     * @apiSuccess {String} lastChapter The ID of the last chapter.
3999     * @apiSuccess {String} teacherId The ID of the teacher.
4000     * @apiSuccess {String} classId The ID of the class.
4001     * @apiSuccess {Object} lastViewedTextInfo The information of the last viewed text.
4002     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.last_viewed_date The last viewed date of the text.
4003     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.class_id The ID of the class.
4004     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.chapter_id The ID of the chapter.
4005     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.preset Indicates if the text is preset.
4006     * @apiSuccess {String} userId The ID of the user.
4007     *
4008     * @apiSuccessExample {json} Success-Response:
4009     *     {
4010     *         "chapterList": [
4011     *             {
4012     *                 "UsersLastViewedTextbook": {
4013     *                     "last_viewed_date": "2023-12-01 10:00:00"
4014     *                 },
4015     *                 "LessonText": {
4016     *                     "chapter_id": "1",
4017     *                     "chapter": "Chapter 1"
4018     *                 }
4019     *             }
4020     *         ],
4021     *         "firstChapter": "1",
4022     *         "lastChapter": "10",
4023     *         "teacherId": "123",
4024     *         "classId": "456",
4025     *         "lastViewedTextInfo": {
4026     *             "UsersLastViewedTextbook": {
4027     *                 "last_viewed_date": "2023-12-01 10:00:00",
4028     *                 "class_id": "456",
4029     *                 "chapter_id": "1",
4030     *                 "preset": "0"
4031     *             }
4032     *         },
4033     *         "userId": "789"
4034     *     }
4035     *
4036     * @apiError {String} status The status of the request (NG).
4037     * @apiError {String} message The error message.
4038     *
4039     * @apiErrorExample {json} Error-Response:
4040     *     {
4041     *         "status": "NG",
4042     *         "message": "Invalid request."
4043     *     }
4044     * 
4045     * @apiSampleRequest off
4046     */
4047    public function result($teacherId, $classId, $firstId, $lastId) {
4048        $user_id = $this->Auth->user('id');
4049        if ($lastId != '') {
4050            $lastId = $this->request->data['lastid'];
4051            $classChapterList = $this->LessonText->find('all',
4052                array(
4053                    'joins' => array(
4054                        array(
4055                            'type'  => 'LEFT',
4056                            'table' => 'users_last_viewed_textbooks',
4057                            'alias' => 'UsersLastViewedTextbook',
4058                            'conditions' => array(
4059                                'UsersLastViewedTextbook.user_id    = ' . $user_id,
4060                                'UsersLastViewedTextbook.class_id   = LessonText.class_id',
4061                                'UsersLastViewedTextbook.chapter_id = LessonText.chapter_id',
4062                                'UsersLastViewedTextbook.preset !=' => 1
4063                            )
4064                        )
4065                    ),
4066                    'fields' => array(
4067                        'UsersLastViewedTextbook.last_viewed_date',
4068                        'LessonText.chapter_id',
4069                        'LessonText.chapter'
4070                    ),
4071                    'conditions' => array(
4072                        'LessonText.class_id' => $classId,
4073                        'LessonText.chapter_id >' => $lastId,
4074                        'LessonText.status' => 1
4075                    ),
4076                    'order' => 'ISNULL(LessonText.orderno), LessonText.orderno ASC, LessonText.chapter_id ASC'
4077                )
4078            );
4079
4080        } else if ($firstId != '') {
4081            $firstId = $this->request->data['firstid'];
4082            $classChapterList = $this->LessonText->find('all',
4083                array(
4084                    'joins' => array(
4085                        array(
4086                            'type'  => 'LEFT',
4087                            'table' => 'users_last_viewed_textbooks',
4088                            'alias' => 'UsersLastViewedTextbook',
4089                            'conditions' => array(
4090                                'UsersLastViewedTextbook.user_id    = ' . $user_id,
4091                                'UsersLastViewedTextbook.class_id   = LessonText.class_id',
4092                                'UsersLastViewedTextbook.chapter_id = LessonText.chapter_id',
4093                                'UsersLastViewedTextbook.preset !=' => 1
4094                            )
4095                        )
4096                    ),
4097                    'fields' => array(
4098                        'UsersLastViewedTextbook.last_viewed_date',
4099                        'LessonText.chapter_id',
4100                        'LessonText.chapter'
4101                    ),
4102                    'conditions' => array(
4103                        'LessonText.class_id' => $classId,
4104                        'LessonText.chapter_id <' => $firstId,
4105                        'LessonText.status' => 1
4106                    ),
4107                    'order' => 'ISNULL(LessonText.orderno), LessonText.orderno ASC, LessonText.chapter_id ASC'
4108                )
4109            );
4110        } else {
4111
4112            $classChapterList = $this->LessonText->find('all',
4113                array(
4114                    'joins' => array(
4115                        array(
4116                            'type'  => 'LEFT',
4117                            'table' => 'users_last_viewed_textbooks',
4118                            'alias' => 'UsersLastViewedTextbook',
4119                            'conditions' => array(
4120                                'UsersLastViewedTextbook.user_id    = ' . $user_id,
4121                                'UsersLastViewedTextbook.class_id   = LessonText.class_id',
4122                                'UsersLastViewedTextbook.chapter_id = LessonText.chapter_id',
4123                                'UsersLastViewedTextbook.preset !=' => 1
4124                            )
4125                        )
4126                    ),
4127                    'fields' => array(
4128                        'UsersLastViewedTextbook.last_viewed_date',
4129                        'LessonText.class_id',
4130                        'LessonText.chapter_id',
4131                        'LessonText.chapter'
4132                    ),
4133                    'conditions' => array(
4134                        'LessonText.class_id' => $classId,
4135                        'LessonText.status' => 1
4136                    ),
4137                    'order' => 'ISNULL(LessonText.orderno), LessonText.orderno ASC, LessonText.chapter_id ASC'
4138                )
4139            );
4140        }
4141
4142        $classChapterFirstLast = $this->LessonText->find('first',
4143            array(
4144                'conditions' => array(
4145                    'LessonText.class_id' => $classId
4146                ),
4147                'fields' => array(
4148                    'MIN(LessonText.chapter_id) as first_chapter',
4149                    'MAX(LessonText.chapter_id) as last_chapter'
4150                )
4151            )
4152        );
4153
4154        if ($classChapterFirstLast) {
4155            $this->set('firstChapter', $classChapterFirstLast[0]['first_chapter']);
4156            $this->set('lastChapter', $classChapterFirstLast[0]['last_chapter']);
4157        } else {
4158            $this->set('firstChapter', '');
4159            $this->set('lastChapter', '');
4160        }
4161
4162        $this->set('teacherId', $teacherId);
4163        $this->set('classId', $classId);
4164        if ($firstId != '') {
4165            $classChapterList = array_reverse($classChapterList);
4166        }
4167
4168        //NC-634
4169        $lastViewedText = $this->UsersLastViewedTextbook->find(
4170            'all',
4171            array(
4172                'conditions' => array(
4173                    'UsersLastViewedTextbook.user_id' => $user_id,
4174                    'UsersLastViewedTextbook.preset !=' => 1
4175                ),
4176                'order' => array('UsersLastViewedTextbook.modified DESC'),
4177                'limit' => 1
4178            )
4179        );
4180
4181        $lastViewedTextInfo = array();
4182        if(isset($lastViewedText[0]) && isset($lastViewedText[0]['UsersLastViewedTextbook'])) {
4183            $lastViewedTextInfo = $lastViewedText[0];
4184        }
4185
4186        $this->set('lastViewedTextInfo', $lastViewedTextInfo);
4187        $this->set('chapterList', $classChapterList);
4188        $this->set('userId', $this->Auth->user('id'));
4189        $this->render('result', 'ajax');
4190    }
4191
4192    /**
4193     * @api {post} /user/waiting/loadMoreComments loadMoreComments()
4194     * @apiName loadMoreComments
4195     * @apiGroup Waiting
4196     * @apiDescription Loads more comments for a specific teacher or counselor in Native Camp. It returns the list of comments and indicates if there are more pages available.
4197     *
4198     * @apiBody {Number} page The page number to load.
4199     * @apiBody {String} teacherId The ID of the teacher.
4200     * @apiBody {Boolean} [isCounseling=false] Indicates if the request is for counseling comments.
4201     * @apiBody {Boolean} [isAvatar=false] Indicates if the request is for avatar comments.
4202     * @apiBody {Number} [order=0] The order of the comments.
4203     * 
4204     * @apiSuccess {Object[]} results The list of comments.
4205     * @apiSuccess {Number} results.id The ID of the comment.
4206     * @apiSuccess {String} results.star The HTML content for the star rating.
4207     * @apiSuccess {Number} results.age The age of the user who made the comment.
4208     * @apiSuccess {String} results.gender The gender of the user who made the comment.
4209     * @apiSuccess {String} results.user_comment The comment text.
4210     * @apiSuccess {String} results.date The date of the comment.
4211     * @apiSuccess {Object} results.textbook The textbook information.
4212     * @apiSuccess {String} results.textbook.textUrl The URL of the textbook.
4213     * @apiSuccess {String} results.textbook.textbook_image The image URL of the textbook.
4214     * @apiSuccess {String} results.textbook.textbook_name_lv1 The level 1 name of the textbook.
4215     * @apiSuccess {String} results.textbook.textbook_name_lv2 The level 2 name of the textbook.
4216     * @apiSuccess {String} results.textbook.textbook_name_lv3 The level 3 name of the textbook.
4217     * @apiSuccess {Number} results.review_id The ID of the review.
4218     * @apiSuccess {Number} results.like_total The total number of likes for the comment.
4219     * @apiSuccess {Number} results.dislike_total The total number of dislikes for the comment.
4220     * @apiSuccess {Number} results.voted Indicates if the user has voted on the comment (0: No, 1: Yes).
4221     * @apiSuccess {Boolean} lastPage Indicates if there are no more pages of comments available.
4222     *
4223     * @apiSuccessExample {json} Success-Response:
4224     *     {
4225     *         "results": [
4226     *             {
4227     *                 "id": 1,
4228     *                 "star": "<div>Star Rating</div>",
4229     *                 "age": 25,
4230     *                 "gender": "Male",
4231     *                 "user_comment": "Great lesson!",
4232     *                 "date": "2023-12-01",
4233     *                 "textbook": {
4234     *                     "textUrl": "http://example.com/textbook",
4235     *                     "textbook_image": "http://example.com/image.jpg",
4236     *                     "textbook_name_lv1": "Level 1",
4237     *                     "textbook_name_lv2": "Level 2",
4238     *                     "textbook_name_lv3": "Level 3"
4239     *                 },
4240     *                 "review_id": 1,
4241     *                 "like_total": 10,
4242     *                 "dislike_total": 2,
4243     *                 "voted": 1
4244     *             }
4245     *         ],
4246     *         "lastPage": false
4247     *     }
4248     *
4249     * @apiError {String} status The status of the request (NG).
4250     * @apiError {String} message The error message.
4251     *
4252     * @apiErrorExample {json} Error-Response:
4253     *     {
4254     *         "status": "NG",
4255     *         "message": "Invalid request."
4256     *     }
4257     * 
4258     * @apiSampleRequest off
4259     */
4260    public function loadMoreComments() {
4261            $this->autoRender = false;
4262            $this->layout = false;
4263            $userId = $this->Auth->user('id');
4264            if ($this->request->is('ajax')) {
4265                $perPage = 4;
4266                $data = $this->request->data;
4267
4268                // - if ajax is from counseling
4269                if (isset($data['isCounseling']) && $data['isCounseling']) {
4270                    $data['teacherId'] = $this->Teacher->getCounselorId();
4271                }
4272
4273                $params = array(
4274                    'order' => isset($data['order']) ? $data['order'] : 0,
4275                    'limit' => $perPage,
4276                    'offset' => $data['page'] * $perPage,
4277                    'userId' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
4278                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
4279                    'lang' => $this->localizeDir
4280                );
4281                $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
4282                $options['language_id'] = $reviewLanguage[0];
4283                $options['not_language_ids'] = $reviewLanguage[1] ?? null;
4284                $options['isAvatar'] = ( isset($data['isAvatar']) ) ? 1 : 0 ;
4285                $commentCount = $this->UsersClassEvaluation->getCommentCount($data['teacherId'], $options);
4286
4287                if (isset($data['isAvatar'])) {
4288                    $avatarParams = array(
4289                        'order' => isset($data['order']) ? $data['order'] : 0,
4290                        'limit' => $perPage,
4291                        'offset' => $data['page'] * $perPage,
4292                        'user_id' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
4293                        'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
4294                        'selfReviewsFlg' => false,
4295                        'avatar_id' => isset($data['teacherId']) ? $data['teacherId'] : 0,
4296                        'lang' => $this->localizeDir
4297                    );
4298
4299                    myTools::initializeApiTunnel(array('AvatarTeacherController'));
4300                    $teachersReviews = new AvatarTeacherController();
4301                    $comments = $teachersReviews->getAllAvatarEvaluation($avatarParams);
4302                    //count avatar reviews
4303                    $commentCount = $teachersReviews->getCountAllEvaluation(array("avatar_id" => isset($data['teacherId']) ? $data['teacherId'] : 0, 'lang' => $this->localizeDir));
4304
4305                } elseif ( isset($data['isCounseling']) ) {
4306                    myTools::initializeApiTunnel(array('TeachersCounselorReviewsController'));
4307                    $teachersReviews = new TeachersCounselorReviewsController();
4308                    $teachersReviews->params = $params;
4309                    $comments = $teachersReviews->getAllCounselEvaluation();
4310                // office teacher
4311                } else {
4312                    myTools::initializeApiTunnel(array('TeachersReviewsController'));
4313                    $teachersReviews = new TeachersReviewsController();
4314                    $params['conditions'] = array(
4315                        'UsersClassEvaluation.teacher_id' => $data['teacherId'],
4316                        'UsersClassEvaluation.approve_flag' => 1,
4317                        'UsersClassEvaluation.user_comment <>' => ''
4318                    );
4319                    $teachersReviews->params = $params;
4320                    $comments = $teachersReviews->getReviews();
4321                }
4322
4323
4324                // - if ajax is from counseling
4325                $view = new View($this, false);
4326                $ctr = 0;
4327                $results = [];
4328                foreach ($comments as $comment) {
4329                    $user = new UserTable($comment['User']);
4330                    $review = new UsersClassEvaluationTable($comment['UsersClassEvaluation']);
4331                    $results[$ctr] = array(
4332                        'id' => $review->id,
4333                        'star' => $view->element('rate', array('rate' => $review->rate)),
4334                        'age' => $user->getAge(),
4335                        'gender' => $user->getGenderComment(),
4336                        'user_comment' => $review->getUserComment(),
4337                        'date' => date('Y-m-d', strtotime($review->getCreatedDate($this->timeDiffSecond)))
4338                    );
4339
4340                    $textbook = $comment['SubTextBook'] ?? null;
4341                    if ($textbook) {
4342                        $notSapuriTextFlg = false;
4343                        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
4344                            $pathLocale = '/'. $this->localizeDir;
4345                        }
4346                        $curTextType = $textbook['textbook_category_type'];
4347                        $textDefaultUrl = $pathLocale."/textbook/page-detail/".$textbook['textbook_category_type_id']."/".$textbook['textbook_connect_id'];
4348                        if (isset($this->studySapuriId)) {
4349                            $notSapuriTextFlg = (isset($this->sapuriTextTypes) && $curTextType != $this->sapuriTextTypes) ? true : false;
4350                        }
4351
4352                        $textbook['textUrl'] = $notSapuriTextFlg ? "javascript:void(0)" : $textDefaultUrl;
4353                        $textbook['textbook_image'] = $textbook['textbook_image'] ?? 'no_image';
4354
4355                        if (empty($textbook['textbook_connect_id'])) {
4356                            $textbook['textUrl'] = 'javascript:void(0)';
4357                            $textbook['textbook_image'] = 'no_image';
4358                            $textbook['textbook_name_lv1'] = '';
4359                            $textbook['textbook_name_lv2'] = '';
4360                            $textbook['textbook_name_lv3'] = '';
4361                        }
4362                    }
4363                    $results[$ctr]['textbook'] = $textbook;
4364
4365                    if ($userId) {
4366                        $results[$ctr]['review_id']  = $review->id;
4367                        $results[$ctr]['like_total'] = $review->like_votes;
4368                        $results[$ctr]['dislike_total'] = $review->dislike_votes;
4369                        $results[$ctr]['voted'] = $comment['UsersReviewVote']['vote'] != '' ? (int)$comment['UsersReviewVote']['vote'] : 0;
4370                    }
4371
4372                    $ctr++;
4373                }
4374            }
4375            $lastPage = (intval($data['page'] * $perPage) + $perPage) >= $commentCount ? true : false;
4376            $this->output($results, $lastPage);
4377        }
4378
4379
4380    private function output($data, $lastPage, $result = 'ok') {
4381        $result = array(
4382                'data' => $data,
4383                'result' => $result,
4384                'lastPage' => $lastPage,
4385            );
4386        echo json_encode($result);
4387        return;
4388    }
4389
4390    /**
4391      * @api {get} /user/waiting/is-can-cancel isCanCancel()
4392      * @apiName isCanCancel
4393      * @apiGroup Waiting
4394      * @apiDescription Checks if the user can cancel a reservation in Native Camp. It returns the status of the cancellation eligibility.
4395      *
4396      * @apiBody {String} [userId] The ID of the user (optional if fromCorporateManagement or fromSapuriTos is set).
4397      * @apiBody {Boolean} [fromCorporateManagement] Indicates if the request is from corporate management.
4398      * @apiBody {Boolean} [fromSapuriTos] Indicates if the request is from Sapuri TOS.
4399      * 
4400      * @apiSuccess {Boolean} canCancel Indicates whether the user can cancel the reservation.
4401      *
4402      * @apiSuccessExample {json} Success-Response:
4403      *     {
4404      *         "canCancel": true
4405      *     }
4406      *
4407      * @apiError {String} status The status of the request (NG).
4408      * @apiError {String} message The error message.
4409      *
4410      * @apiErrorExample {json} Error-Response:
4411      *     {
4412      *         "status": "NG",
4413      *         "message": "Invalid request."
4414      *     }
4415      * 
4416      * @apiSampleRequest off
4417      */
4418    public function isCanCancel() {
4419        $this->autoRender = false;
4420        $get = $this->request->query;
4421
4422        // NC-8336
4423        if (
4424            isset($get['userId']) &&
4425            (isset($get['fromCorporateManagement']) || isset($get['fromSapuriTos']))
4426        ) {
4427            // get user data
4428            $this->User->openDBReplica();
4429            $user = $this->User->find('first', [
4430                'conditions' => ['User.id' => $get['userId']],
4431                'recursive' => -1
4432            ]);
4433            $this->User->closeDBReplica();
4434            $user = $user ? $user['User'] : [];
4435        } else {
4436            $get['userId'] = $this->Auth->user('id');
4437            $user = $this->sharedUserData['User'];
4438        }
4439
4440        $get['nc_terminal_type'] = 1; // pc
4441        $get['timeDiffSecond'] = $this->timeDiffSecond;
4442        $get['localizeDir'] = $this->localizeDir;
4443        $get['user'] = $user;
4444
4445        // open tunnel
4446        myTools::initializeApiTunnel(['ReservationController']);
4447
4448        // initialize controller
4449        $rc = new ReservationController();
4450
4451        // set data
4452        $rc->params = $get;
4453
4454        // process
4455        return $rc->isCanCancel();
4456    }
4457
4458    /**
4459     * @api {get} /user/waiting/convertString convertString()
4460     * @apiName convertString
4461     * @apiGroup Waiting
4462     * @apiDescription Converts a given string by disabling HTML tags and returns the result along with an ID name.
4463     *
4464     * @apiBody {String} _string The string to be converted.
4465     * @apiBody {String} id_name The ID name to be returned.
4466     * 
4467     * @apiSuccess {Object} result The result object.
4468     * @apiSuccess {String} result.res The converted string with HTML tags disabled.
4469     * @apiSuccess {String} result.idName The ID name.
4470     *
4471     * @apiSuccessExample {json} Success-Response:
4472     *     {
4473     *         "res": "Converted string",
4474     *         "idName": "exampleId"
4475     *     }
4476     *
4477     * @apiError {String} status The status of the request (NG).
4478     * @apiError {String} message The error message.
4479     *
4480     * @apiErrorExample {json} Error-Response:
4481     *     {
4482     *         "status": "NG",
4483     *         "message": "Invalid request."
4484     *     }
4485     * 
4486     * @apiSampleRequest off
4487     */
4488    public function convertString() {
4489        $this->autoRender = false;
4490        $string = $this->request->query['_string'];
4491        $idName = $this->request->query['id_name'];
4492        return json_encode(array('res' => myTools::disableHTMLTags($string), 'idName' => $idName));
4493    }
4494
4495    //not used function
4496    public function getTextbookOption($flag = '') {
4497        $this->autoRender = false;
4498        $result = array();
4499        $textbook_type = 0;
4500        $lessonNowReservation = false;
4501        $textbook_category_type = 0;
4502        $lesson_text_id = 0;
4503
4504        $userId = $this->Auth->user('id');
4505        $teacherId = $this->request->data['teacher_id'];
4506
4507        // NJ-9489 : check if membership is allowed to display counselor information
4508        $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
4509        $hideCouselorFromMember = 0;
4510
4511        if (
4512            !$_userPaymentPlan ||
4513            in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
4514        ) {
4515              $hideCouselorFromMember = 1;
4516        }
4517
4518        $textbookOptionArr = array();
4519        $Textbook = new TextbookController;
4520
4521        # course variable
4522        $getCourseArr = array(
4523            'teacher_id' => $teacherId,
4524            'flag' => $flag,
4525            'user_id' => $userId
4526        );
4527
4528        $course = $this->LessonText->getCourse($getCourseArr);
4529
4530            # User last viewed text book
4531            $getLastArr = array(
4532                'user_id' => $userId,
4533                'type' => 'course',
4534                'teacher_id' => $teacherId,
4535                'flag' => $flag
4536            );
4537            $courseDefault = $this->LessonText->getLastViewedBook( $getLastArr );
4538            $courseId = $courseDefault['courseId'] ?? null;
4539            $curriculumId = $courseDefault['curriculumId'] ?? null;
4540            $lessonTextId = $courseDefault['lessonTextId'] ?? null;
4541
4542        $textbookOptionArr['courseArr'] = $course;
4543        $textbookOptionArr['courseSelected'] = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4544
4545        $dataSetOption = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4546        $textbookOptionArr['courseCurriculumId'] = $curriculumId;
4547        $textbookOptionArr['courseCurriculumArr'] = $dataSetOption;
4548        $courseCurriculumSelected = $textbookOptionArr['courseCurriculumArr']['Curriculum'][$curriculumId] ?? null;
4549        $textbookOptionArr['courseCurriculumSelected'] = $courseCurriculumSelected['data'][$lessonTextId] ?? null;
4550        $textbookOptionArr['courseCurriculumSelected']['badge'] = isset($courseDefault['textbook_info']['Curriculum']['badge']) ? $courseDefault['textbook_info']['Curriculum']['badge'] : 0;
4551        # category variable
4552        $getCategoryArr = array(
4553            'teacher_id' => $teacherId,
4554            'flag' => $flag,
4555            'user_id' => $userId
4556        );
4557        $category = $this->LessonText->getCategory($getCategoryArr);
4558
4559            # User last viewed text book
4560            $getLastArr = array(
4561                'user_id' => $userId,
4562                'type' => 'category',
4563                'teacher_id' => $teacherId,
4564                'flag' => $flag
4565            );
4566            $categoryDefault = $this->LessonText->getLastViewedBook( $getLastArr );
4567            $classId = $categoryDefault['classId'] ?? null;
4568            $categoryLessonTextId = $categoryDefault['lessonTextId'] ?? null;
4569
4570        $textbookOptionArr['categoryArr'] = $category;
4571        $textbookOptionArr['categorySelected'] = isset($textbookOptionArr['categoryArr'][$classId]) ? $textbookOptionArr['categoryArr'][$classId] : 0;
4572        $textbookArr = $this->LessonText->getTextBookCategory(($textbookOptionArr['categorySelected']['ClassMaster']['id'] ?? null),$userId, $flag);
4573        $textbookOptionArr['categoryClassArr'] = $textbookArr['data'] ?? [];
4574        $textbookOptionArr['categoryClassSelected'] = isset($textbookOptionArr['categoryClassArr'][$categoryLessonTextId]) ? $textbookOptionArr['categoryClassArr'][$categoryLessonTextId] : 0;
4575
4576        # ------ default user textbook in iframe
4577        $defaultTextbookType = 2;
4578        $getLastArr = array(
4579            'user_id' => $userId,
4580            'type' => 'all',
4581            'teacher_id' => $teacherId,
4582            'flag' => $flag
4583        );
4584        $lastBookType = $this->LessonText->getLastViewedBook( $getLastArr );
4585        $defaultTextbookType = $lastBookType['textbook_type'] ?? null;
4586
4587        # - since course is the first option shown
4588        if ( $defaultTextbookType ) {
4589            if ( $defaultTextbookType == 1 ) {
4590                # Course
4591                $defaulClassId = $textbookOptionArr['courseCurriculumSelected']['class_id'] ?? 0;
4592                $defaulChapterId = $textbookOptionArr['courseCurriculumSelected']['chapter_id'] ?? 0;
4593            } else {
4594                # Category
4595                $defaulClassId = isset($textbookOptionArr['categoryClassSelected']['LessonText']['class_id']) ? $textbookOptionArr['categoryClassSelected']['LessonText']['class_id'] : 0;
4596                $defaulChapterId = isset($textbookOptionArr['categoryClassSelected']['LessonText']['chapter_id']) ? $textbookOptionArr['categoryClassSelected']['LessonText']['chapter_id'] : 0;
4597            }
4598        } else {
4599            # if the user don't have lastviewed ( Category )
4600            $defaulClassId = $textbookOptionArr['categoryClassSelected']['LessonText']['class_id'] ?? null;
4601            $defaulChapterId = $textbookOptionArr['categoryClassSelected']['LessonText']['chapter_id'] ?? null;
4602        }
4603        //use textbook of the reserve schedule
4604        $textbookOptionArr['defaulTextbook'] = "/HtmlTextbook/index?class_id={$defaulClassId}&chapter_id={$defaulChapterId}";
4605        $textbookOptionArr['textbook_type'] = $defaultTextbookType;
4606        $textbookOptionArr['hide_switch'] = false;
4607        # ---------------- iframe end
4608
4609        //set flag for hide counselor textbook
4610        $textbookOptionArr['hide_counselor_info'] = $hideCouselorFromMember;
4611
4612        $view = new View($this, false);
4613        $result['option'] = $view->element('modal_textbook_selection',array('optionArr' => $textbookOptionArr));
4614        $result['textbook_default'] = $textbookOptionArr['defaulTextbook'];
4615        $result['textbook_type'] = $textbookOptionArr['textbook_type'];
4616
4617        return json_encode($result);
4618    }
4619
4620    /**
4621     * @api {post} /user/waiting/getAllTextbookOption getAllTextbookOption()
4622     * @apiName getAllTextbookOption
4623     * @apiGroup Waiting
4624     * @apiDescription Retrieves all textbook options for the authenticated user in Native Camp. It returns various information about the available textbooks, including courses, series, and user preferences.
4625     *
4626     * @apiBody {String} [teacher_id] The ID of the teacher.
4627     * @apiBody {String} [flag=all] The environment flag (e.g., lesson_now, reservation).
4628     * @apiBody {String} [live_flag] The live flag.
4629     * @apiBody {String} [action] The action to perform (e.g., setNextTextbookChapter).
4630     * @apiBody {String} [localizeDir] The localization directory.
4631     * @apiBody {String} [connectId] The connect ID of the textbook.
4632     * @apiBody {String} [resFlag] The reservation flag.
4633     * @apiBody {String} [textbook_level] The textbook level.
4634     * @apiBody {Boolean} [favorite_textbook_only=0] Indicates if only favorite textbooks should be retrieved.
4635     * 
4636     * @apiSuccess {Object} result The result object.
4637     * @apiSuccess {String} result.option The HTML content for the textbook options.
4638     * @apiSuccess {Boolean} result.levelFiltered Indicates if the textbooks are filtered by level.
4639     * @apiSuccess {String} result.textbook_default The default textbook URL.
4640     * @apiSuccess {Number} result.textbook_type The type of the textbook (1: Course, 2: Series).
4641     * @apiSuccess {Boolean} result.reservation_flag Indicates if the textbook is for reservation.
4642     * @apiSuccess {Boolean} result.disable_button_flag Indicates if the button should be disabled.
4643     * @apiSuccess {Boolean} result.textbook_live_lesson_flg Indicates if the textbook is for live lessons.
4644     * @apiSuccess {Object} result.user_preset_textbook_data The user preset textbook data.
4645     * @apiSuccess {Number} result.user_preset_textbook_data.id The ID of the textbook category.
4646     * @apiSuccess {Number} result.user_preset_textbook_data.connect_id The connect ID of the textbook.
4647     * @apiSuccess {Number} result.user_preset_textbook_data.sub_cat_id The subcategory ID of the textbook.
4648     * @apiSuccess {Number} result.user_preset_textbook_data.textbook_id The ID of the textbook.
4649     * @apiSuccess {Boolean} result.user_preset_textbook_data.display_flag Indicates if the textbook should be displayed.
4650     * @apiSuccess {Number} result.user_preset_textbook_data.textbook_type The type of the textbook.
4651     * @apiSuccess {Boolean} result.userPresetDisplayFlg Indicates if the user preset display flag is set.
4652     *
4653     * @apiSuccessExample {json} Success-Response:
4654     *     {
4655     *         "option": "<div>Textbook Options</div>",
4656     *         "levelFiltered": false,
4657     *         "textbook_default": "/HtmlTextbook/index?connect_id=123&html_dir=dir&chapter_id=1&isFromModal=1",
4658     *         "textbook_type": 1,
4659     *         "reservation_flag": true,
4660     *         "disable_button_flag": 0,
4661     *         "textbook_live_lesson_flg": true,
4662     *         "user_preset_textbook_data": {
4663     *             "id": 1,
4664     *             "connect_id": 123,
4665     *             "sub_cat_id": 2,
4666     *             "textbook_id": 3,
4667     *             "display_flag": true,
4668     *             "textbook_type": 1
4669     *         },
4670     *         "userPresetDisplayFlg": true
4671     *     }
4672     *
4673     * @apiError {String} status The status of the request (NG).
4674     * @apiError {String} message The error message.
4675     *
4676     * @apiErrorExample {json} Error-Response:
4677     *     {
4678     *         "status": "NG",
4679     *         "message": "Invalid request."
4680     *     }
4681     * 
4682     * @apiSampleRequest off
4683     */
4684    public function getAllTextbookOption() {
4685        // increase time limit
4686        set_time_limit(60);
4687        // increase max execution time
4688        ini_set('max_execution_time', 60);
4689        // inscrease memory limit
4690        myTools::alterPHPMemoryLimit('512M');
4691        $this->autoRender = false;
4692        $result = array();
4693        $textbook_category_type = 0;
4694        $lesson_text_id = 0;
4695        //set user id
4696        $userId = $this->Auth->user('id') ?? false;
4697        $param = array('user_id' => $userId);
4698        $textbookOptionArr = array();
4699        $teacherId = isset($this->request->data['teacher_id'])? $this->request->data['teacher_id'] : null;
4700        $envFlag = isset($this->request->data['flag'])? $this->request->data['flag'] : 'all';
4701        $liveFlag = isset($this->request->data['live_flag']) ? $this->request->data['live_flag'] : null;
4702        $connectIdCourse = $connectIdSeries = null;
4703        $action = (isset($this->request->data['action']) && $this->request->data['action'] == 'setNextTextbookChapter') ? $this->request->data['action'] : null;
4704        $isCourse = false;
4705        $teacherBadgeTextbooks     = array();
4706        $counselorTeacher = 0;
4707        $studentFinishedCallanLevelCheck = ClassRegistry::init('User')->hasFinishedCallanLevelCheck(array(
4708            'user_id' => $userId,
4709            'removeRelatedData' => true
4710        ));
4711
4712        // - if has localize directory
4713        if (isset($this->request->data['localizeDir']) && mb_strlen($this->request->data['localizeDir'])) {
4714            $this->localizeDir = $this->request->data['localizeDir'];
4715        }        
4716
4717        // NJ-5836
4718        // set params
4719        $displayRestrictionParams = array(
4720            'lang' => $this->localizeDir
4721        );
4722
4723        // get display restriction setting
4724        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
4725        
4726        //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
4727        $userValidForSSBEDT = $this->userValidForSSBEDT();
4728
4729        //NC-8911: check user if for global course
4730        $isUserForGlobalCourse = false;
4731        if(isset($this->localizeDir) && $this->localizeDir !== Configure::read('default.user_language')) {
4732            $isUserForGlobalCourse = true;
4733        }
4734
4735        // NJ-9489 : check if membership is allowed to display counselor information
4736        $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
4737        $hideCouselorFromMember = 0;
4738
4739        if (
4740            !$_userPaymentPlan ||
4741            in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
4742        ) {
4743          $hideCouselorFromMember = 1;
4744        }
4745
4746        // check for counselor type teacher
4747        if ( $teacherId && $envFlag == "lesson_now" ) {
4748            $this->Teacher->openDBReplica();
4749            $counselorTeacher = $this->Teacher->find('count', array(
4750                'conditions' => array(
4751                    'Teacher.id' => $teacherId,
4752                    'Teacher.counseling_flg' => 1,
4753                    'Teacher.status' => 1
4754                ),
4755                'recursive' => -1
4756            ));
4757            $this->Teacher->closeDBReplica();
4758        }
4759        // filter textbook with teacher badge for dropwdown only : display all textbooks for Textbook page
4760        if ( $teacherId && !$counselorTeacher && $envFlag != "all" ) {
4761            $teacherBadgeTextbooks = ClassRegistry::init('TeacherBadge')->getTeacherBadge(array('teacher_id' => $teacherId, 'flag' => $envFlag));
4762        }
4763
4764        // check if student has reserved entry level
4765        $lessonScheduleModel = ClassRegistry::init('LessonSchedule');
4766        $lessonScheduleModel->clear();
4767        $hasReservedCallanLevelCheck = $lessonScheduleModel->hasReservedCallanLevelCheck(array('user_id' => $userId));
4768
4769        // Default Textbook
4770        $defaultParam = array(
4771            'env_flag' => $envFlag,
4772            'reservation_flag' => isset($this->request->data['resFlag'])? $this->request->data['resFlag'] : null,
4773            'select_method' => "first",
4774            'teacher_id' => $teacherId,
4775            'user_id' => $userId,
4776            'load_description' => false,
4777            'userValidForSSBEDT' => $userValidForSSBEDT,
4778            'user_locale' => $this->localizeDir,
4779            'isUserForGlobalCourse' => $isUserForGlobalCourse,
4780            'isCouncelor' => $counselorTeacher,
4781            'joinPreTextbookId' => ( !empty($teacherBadgeTextbooks['textbookIdArray']) && count($teacherBadgeTextbooks['textbookIdArray']) > 100 ) ? true : false,
4782            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4783            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4784            'removeRelatedData' => true,
4785            'displayRestriction' => $displayRestriction,
4786            'fetch_favorite' => true
4787        );
4788
4789        if (isset($this->request->data['connectId']) && !empty($this->request->data['connectId'])) {
4790            $defaultParam['connect_id'] = $this->request->data['connectId'];
4791        }
4792
4793        // - add additional parametes for global textbook
4794        if (isset($this->localizeDir) && in_array($this->localizeDir,Configure::read("global_textbook_support_languages"))) {
4795            $defaultParam['user_locale'] = $this->localizeDir;
4796        }
4797        $defaultTextbookData = $this->Textbook->getTextbooks($defaultParam);
4798        // if default textbook category is callan and student has yet to finish callan level check
4799        if (
4800            (isset($defaultTextbookData['res_data']['TextbookCategory']['textbook_category_type']) && $defaultTextbookData['res_data']['TextbookCategory']['textbook_category_type'] == 2)
4801            && (isset($defaultTextbookData['res_data']['Textbook']['callan_level_check']) && !$defaultTextbookData['res_data']['Textbook']['callan_level_check'])
4802            && !$studentFinishedCallanLevelCheck
4803        ) {
4804            $defaultParam['tb_default_levelcheck'] = true;
4805            $defaultTextbookData = $this->Textbook->getTextbooks($defaultParam);
4806
4807        // if not callan
4808        } else {
4809            //  NC-7592 - set next textbook chapter/series within the same category
4810            if ($action !== null && $action === 'setNextTextbookChapter') {
4811                $textbookDatails = isset($defaultTextbookData['res_data']) && isset($defaultTextbookData['res_data']['Textbook']) ? $defaultTextbookData['res_data']['Textbook'] : null;
4812                $textbookConnectDetails = $defaultTextbookData['res_data']['TextbookConnect'] ?? null;
4813                $allTextbookParams = array(
4814                    'category_id' => $textbookConnectDetails['category_id'] ?? null,
4815                    'connect_id' => $textbookConnectDetails['id'] ?? null,
4816                    'subcategory_id' => $textbookConnectDetails['subcategory_id'] ?? null,
4817                    'textbook_main_topic_id' => isset($textbookDatails['main_topic_id']) && $textbookDatails['main_topic_id'] ? $textbookDatails['main_topic_id'] : null,
4818                );
4819                $allTextbookChapters = $this->TextbookConnect->getTextbookPrevAndNextFunction($allTextbookParams);
4820                // if has next textbook chapter, preset
4821                if (
4822                    is_array($allTextbookChapters) && !is_null($allTextbookChapters)
4823                    && ($allTextbookChapters['next'] !== '' && !is_null($allTextbookChapters['next']))
4824                ) {
4825                    $newPresetTextbookConnectId = $allTextbookChapters['next'];
4826                    $saveParams = array('userId' => $userId, 'connectId' => $newPresetTextbookConnectId);
4827                    $saveNextTextbookChapter = $this->saveTextbookPreset($saveParams);
4828                    // pull new default data
4829                    $defaultTextbookData = $this->Textbook->getTextbooks($defaultParam);
4830                }
4831            }
4832        }
4833        $defaultTextbook = $defaultTextbookData['res_data'] ?? [];
4834        $defaultConnectId = $defaultTextbook['TextbookConnect']['id'] ?? null;
4835        $defaultTextbookCategoryId = $defaultTextbook['TextbookCategory']['id'] ?? null;
4836        // course
4837        if (isset($defaultTextbook['TextbookCategory']['type_id']) && $defaultTextbook['TextbookCategory']['type_id'] == 1) {
4838            $connectIdCourse = $defaultTextbook['TextbookConnect']['id'] ?? null;
4839            $isCourse = true;
4840        }
4841        // series
4842        if (isset($defaultTextbook['TextbookCategory']['type_id']) && $defaultTextbook['TextbookCategory']['type_id'] == 2) {
4843            $connectIdSeries = $defaultTextbook['TextbookConnect']['id'] ?? null;
4844        }
4845        // Get all Book
4846        $getAllBookArr = array(
4847            'env_flag' => $envFlag,
4848            'teacher_id' => $teacherId,
4849            'select_method' => 'all',
4850            'mode' => 'combine',
4851            'preset' => 'off',
4852            'user_id' => $userId,
4853            'load_description' => false,
4854            'userValidForSSBEDT' => $userValidForSSBEDT,
4855            'user_locale' => $this->localizeDir,
4856            'isUserForGlobalCourse' => $isUserForGlobalCourse,
4857            'is_course' => $isCourse,
4858            'isCouncelor' => $counselorTeacher,
4859            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4860            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4861            'removeRelatedData' => true,
4862            'displayRestriction' => $displayRestriction,
4863            'ranked_textbook' => ($this->isStudySapuriTosUser || $this->isStudySapuriUser) ? false : true,
4864            'fetch_favorite' => true
4865        );
4866
4867        if (isset($this->request->data['textbook_level']) && !empty($this->request->data['textbook_level'])) {
4868            $getAllBookArr['textbook_level'] = $this->request->data['textbook_level'];
4869        }
4870        
4871        // NC-7593 add favorites on textbook return
4872        if ($userId) {
4873            $params = array("user_id" => $userId);
4874            $textbookFavData = $this->UserTextbookFavorite->getUserFavoriteTextbooks($params);
4875            $getAllBookArr['textbookFavData'] = $textbookFavData;
4876        }
4877
4878        // - add additional parametes for global textbook
4879        if (isset($this->localizeDir) && in_array($this->localizeDir,Configure::read("global_textbook_support_languages"))) {
4880            $getAllBookArr['user_locale'] = $this->localizeDir;
4881        }
4882
4883        $allBookData = $this->Textbook->getTextbooks($getAllBookArr);
4884        $allBook = $allBookData['res_data'] ?? [];
4885
4886        // course variable
4887        $course = $allBook['course'] ?? [];
4888        $getCoursePresetArr = array(
4889            'env_flag' => 'all',
4890            'textbook_type' => 1,
4891            'select_method' => "first",
4892            'teacher_id' => $teacherId,
4893            'connect_id' => $connectIdCourse,
4894            'user_id' => $userId,
4895            'user_locale' => $this->localizeDir,
4896            'load_description' => false,
4897            'isCouncelor' => $counselorTeacher,
4898            'isForReservation' => ($envFlag == 'reservation') ? true : false,
4899            'joinPreTextbookId' => ( !empty($teacherBadgeTextbooks['textbookIdArray']) && count($teacherBadgeTextbooks['textbookIdArray']) > 100 ) ? true : false,
4900            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4901            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4902            'removeRelatedData' => true,
4903            'displayRestriction' => $displayRestriction,
4904            'fetch_favorite' => true
4905        );
4906        $coursePresetData = $this->Textbook->getTextbooks($getCoursePresetArr);
4907        $coursePreset = $coursePresetData['res_data'] ?? [];
4908
4909        // User last viewed text book
4910        $courseId = $coursePreset['TextbookCategory']['id'] ?? null;
4911        $courseSubCatId = $coursePreset['TextbookSubcategory']['id'] ?? null;
4912        $courseSubCatBadge = isset($coursePreset['TextbookSubcategory']['badge']) && $coursePreset['TextbookSubcategory']['badge'] ? $coursePreset['TextbookSubcategory']['badge'] : null;
4913        $courseConnectId = $coursePreset['TextbookConnect']['id'] ?? null;
4914        $courseLessonTextId = $coursePreset['Textbook']['id'] ?? null;
4915
4916
4917        $textbookOptionArr['courseArr'] = $course;
4918        $textbookOptionArr['courseSelected'] = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4919
4920        $dataSetOption = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4921
4922        $textbookOptionArr['courseSubCatId'] = $courseSubCatId;
4923
4924        $textbookOptionArr['courseSubCatArr'] = $dataSetOption;
4925
4926        $courseSubCatSelected = $textbookOptionArr['courseSubCatArr']['TextbookSubcategory'][$courseSubCatId] ?? null;
4927        $textbookOptionArr['courseSubCatSelected'] = $courseSubCatSelected['textbooks'][$courseConnectId] ?? null;
4928        $textbookOptionArr['courseSubCatSelected']['index_position'] = isset($coursePreset['Textbook']['index_position']) && $coursePreset['Textbook']['index_position'] ? $coursePreset['Textbook']['index_position'] : null;
4929        $textbookOptionArr['courseSubCatSelected']['badge'] = $courseSubCatBadge;
4930
4931        // category variable
4932        $series = $allBook['series'] ?? [];
4933        $getSeriesPresetArr = array(
4934            'env_flag' => 'all',
4935            'textbook_type' => 2,
4936            'select_method' => "first",
4937            'connect_id' => $connectIdSeries,
4938            'user_id' => $userId,
4939            'load_description' => false,
4940            'userValidForSSBEDT' => $userValidForSSBEDT,
4941            'user_locale' => $this->localizeDir,
4942            'isUserForGlobalCourse' => false,
4943            'isCouncelor' => $counselorTeacher,
4944            'isForReservation' => ($envFlag == 'reservation') ? true : false,
4945            'removeRelatedData' => true,
4946            'displayRestriction' => $displayRestriction
4947        );
4948        $seriesPresetData = $this->Textbook->getTextbooks($getSeriesPresetArr);
4949        $seriesPreset = $seriesPresetData['res_data'] ?? [];
4950
4951        // User last viewed text book
4952        $seriesId = $seriesPreset['TextbookCategory']['id'] ?? null;
4953        $seriesSubCatId = $seriesPreset['TextbookSubcategory']['id'] ?? null;
4954        $seriesSubCatBadge = isset($seriesPreset['TextbookSubcategory']['badge']) ? $seriesPreset['TextbookSubcategory']['badge'] : null;
4955        $seriesConnectId = $seriesPreset['TextbookConnect']['id'] ?? null;
4956
4957
4958        $textbookOptionArr['seriesArr'] = $series;
4959        $textbookOptionArr['seriesSpecialArr'] = $series;
4960        $textbookOptionArr['seriesSelected'] = isset($textbookOptionArr['seriesArr'][$seriesSubCatId]) ? $textbookOptionArr['seriesArr'][$seriesSubCatId] : 0;
4961
4962        $textbookOptionArr['seriesSubCatId'] = $seriesSubCatId;
4963        $textbookOptionArr['seriesSubCatSelected'] = $series[$seriesSubCatId] ?? null;
4964        $textbookOptionArr['seriesTextbookArr'] = $series[$seriesSubCatId]['Textbook'] ?? [];
4965        $textbookOptionArr['seriesTextbookSelected'] = $series[$seriesSubCatId]['Textbook'][$seriesConnectId] ?? null;
4966        $textbookOptionArr['seriesTextbookSelected']['index_position'] = $seriesPreset['Textbook']['index_position'] ?? null;
4967        $textbookOptionArr['seriesSubCatSelected']['badge'] = $seriesSubCatBadge;
4968
4969        $getSubcatParams = array(
4970            'reservation_flag' => isset($this->request->data['resFlag'])? $this->request->data['resFlag'] : null,
4971            'teacher_id' => $teacherId,
4972            'category_id' => $defaultTextbookCategoryId,
4973            'env_flag' => $envFlag,
4974            'arrange_data' => "branch",
4975            'user_id' => $userId,
4976            'user_locale' => $this->localizeDir,
4977            'userValidForSSBEDT' => true,
4978            'isCouncelor' => $counselorTeacher,
4979            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4980            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4981            'removeRelatedData' => true,
4982            'fetch_favorite' => true
4983        );
4984        $getSubCategoryArr = $this->Textbook->getTextbooks($getSubcatParams);
4985
4986        // TextbookSubcategory
4987        if ( $defaultTextbook && ( isset( $getSubCategoryArr['res_data'] ) && $getSubCategoryArr['res_data'] ) ) {
4988            $subCategoryData = $getSubCategoryArr['res_data'];
4989            $subCategoryId = $defaultTextbook['TextbookSubcategory']['id'] ?? null;
4990            $mainTopicTextbookId = isset($defaultTextbook['Textbook']['id']) && $defaultTextbook['Textbook']['id'] ? $defaultTextbook['Textbook']['id'] : null ;
4991            $textbookMainTopicId = isset($defaultTextbook['Textbook']['main_topic_id']) && $defaultTextbook['Textbook']['main_topic_id'] ? $defaultTextbook['Textbook']['main_topic_id'] : null ;
4992
4993            if ( $this->localizeDir != Configure::read('default.user_language') ) {
4994                $subCategoryName  = isset( $defaultTextbook['GlobalTextbookSubcategory']['gl_name'] ) && $defaultTextbook['GlobalTextbookSubcategory']['gl_name'] ? $defaultTextbook['GlobalTextbookSubcategory']['gl_name'] : ( isset($defaultTextbook['TextbookSubcategory']['english_name']) && $defaultTextbook['TextbookSubcategory']['english_name'] ? $defaultTextbook['TextbookSubcategory']['english_name'] : $defaultTextbook['TextbookSubcategory']['name'] ) ;
4995            } else {
4996                $subCategoryName  = $defaultTextbook['TextbookSubcategory']['name'];
4997            }
4998
4999            // check for main topic overide subcategory name for daily news
5000            if ( $mainTopicTextbookId && $textbookMainTopicId ) {
5001                $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
5002                $textbookMainTopicName = ClassRegistry::init('Textbook')->getTextbookMainTopicName($mainTopicTextbookId,$langId);
5003                if ($textbookMainTopicName) { 
5004                    $subCategoryName = $textbookMainTopicName; 
5005                }
5006            }
5007
5008            $textbookOptionArr['subCategoryData'] = $subCategoryData;
5009            $textbookOptionArr['subCategoryId'] = $subCategoryId;
5010            $textbookOptionArr['subCategoryName'] = $subCategoryName;
5011
5012            if ($envFlag == 'reservation') {
5013            $textbookOptionArr['subCategoryId'] = $subCategoryId;
5014                $textbookOptionArr['selectedSubcatTeacherTotalTextbookBadge'] = (isset($subCategoryData[$subCategoryId]['TextbookSubcategory']['teacher_total_textbook_badge'])) ? $subCategoryData[$subCategoryId]['TextbookSubcategory']['teacher_total_textbook_badge'] : 0;
5015            }
5016        }
5017
5018        // check daily news category
5019        $dailyNewsCat = false;
5020        $dailyTopicsCat = false;
5021        $textbookObj = null;
5022        if ( isset($defaultTextbook['TextbookConnect']['category_id']) && $defaultTextbook['TextbookConnect']['category_id'] == Configure::read('daily_news_cat_id.series') ) {
5023            $dailyNewsCat = true;
5024            $textbookObj = $this->Textbook;
5025        }
5026        if ( isset($defaultTextbook['TextbookConnect']['category_id']) && $defaultTextbook['TextbookConnect']['category_id'] == Configure::read('daily_topics_textbook.category_id') ) {
5027            $dailyTopicsCat = true;
5028            $textbookObj = $this->Textbook;
5029        }
5030                $eikenEnable = ( $envFlag == 'lesson_now' && isset($defaultTextbook['TextbookConnect']['category_id']) && in_array($defaultTextbook['TextbookConnect']['category_id'], Configure::read('eiken_category_ids')));
5031        // Textbook chapters
5032
5033        // Course
5034        if ( isset($defaultTextbook['TextbookCategory']['type_id']) && $defaultTextbook['TextbookCategory']['type_id'] == 1 ) {
5035            $textbookChapterArr['textbooks'] = $courseSubCatSelected['textbooks'] ?? [];
5036            $selectedTextbookArr = $textbookOptionArr['courseSubCatSelected'];
5037        }
5038        // Series
5039        if ( isset($defaultTextbook['TextbookCategory']['type_id']) && $defaultTextbook['TextbookCategory']['type_id'] == 2 ) {
5040            $textbookChapterArr['textbooks'] = $textbookOptionArr['seriesTextbookArr'];
5041            $selectedTextbookArr = $textbookOptionArr['seriesTextbookSelected'];
5042        }
5043
5044        $textbookOptionArr['dailyNewsCat'] = $dailyNewsCat;
5045        $textbookOptionArr['dailyTopicsCat'] = $dailyTopicsCat;
5046        $textbookOptionArr['textbookObj'] = $textbookObj;
5047        $textbookOptionArr['courseSubCatArr'] = $textbookChapterArr ?? [];
5048        $textbookOptionArr['courseSubCatSelected'] = $selectedTextbookArr ?? [];
5049        $textbookOptionArr['hasFinishedCallanEntry'] = $studentFinishedCallanLevelCheck;
5050        $textbookOptionArr['textbookCategoryType'] = $defaultTextbook['TextbookCategory']['textbook_category_type'] ?? 0;
5051        $textbookOptionArr['eikenEnable'] = $eikenEnable;
5052        $textbookOptionArr['favorite_textbook_only'] = isset($this->request->data['favorite_textbook_only']) ? $this->request->data['favorite_textbook_only'] : 0;
5053
5054        $defaultDir = $defaultTextbook['Textbook']['html_directory'] ?? null;
5055        $defaultChapId = $defaultTextbook['Textbook']['chapter_id'] ?? null;
5056        $defaultBagde = isset($defaultTextbook['TextbookSubcategory']['badge'])?$defaultTextbook['TextbookSubcategory']['badge']:null;
5057
5058        //use textbook of the reserve schedule
5059        $textbookOptionArr['defaulTextbook'] = "/HtmlTextbook/index?connect_id={$defaultConnectId}&html_dir={$defaultDir}&chapter_id={$defaultChapId}&isFromModal=1";
5060        $textbookOptionArr['textbook_type'] = isset($defaultTextbook['TextbookCategory']['type_id'])? $defaultTextbook['TextbookCategory']['type_id'] : 0;
5061        $textbookOptionArr['hide_switch'] = ($textbook_category_type == 2);
5062        $textbookOptionArr['teacher_badge'] = $defaultBagde;
5063        $result['disable_button_flag'] = 0;
5064        # ---------------- iframe end
5065
5066        $view = new View($this, false);
5067
5068        //NJ-2601 : NJ-24096
5069        if ($envFlag == 'reservation') {
5070            $selectedDataTextbook = ($textbookOptionArr['textbook_type'] == 1) ? $textbookOptionArr['courseSelected'] : $textbookOptionArr['seriesSubCatSelected'];
5071            $textbookLiveLessonFlg = isset($selectedDataTextbook['TextbookCategory']['live_lesson_flg']) ? $selectedDataTextbook['TextbookCategory']['live_lesson_flg'] : false;
5072            if (isset($this->request->data['connectId']) && !empty($this->request->data['connectId']) && isset($defaultTextbook['TextbookCategory']['display_flag']) && $defaultTextbook['TextbookCategory']['display_flag']) {
5073                $result['user_preset_textbook_data']['id'] = $selectedDataTextbook['TextbookCategory']['id'] ?? null; //cat id
5074                $result['user_preset_textbook_data']['connect_id'] = $selectedTextbookArr['connect_id'] ?? null; //connect id
5075                $result['user_preset_textbook_data']['sub_cat_id'] = isset($selectedDataTextbook['TextbookSubcategory']['id']) ? $selectedDataTextbook['TextbookSubcategory']['id'] : 0;
5076                $result['user_preset_textbook_data']['textbook_id'] = (isset($selectedTextbookArr['connect_id']) && isset($selectedDataTextbook['Textbook'][$selectedTextbookArr['connect_id']]['id']))
5077                    ? $selectedDataTextbook['Textbook'][$selectedTextbookArr['connect_id']]['id']
5078                    : 0;
5079                $result['user_preset_textbook_data']['display_flag'] = (isset($selectedTextbookArr['connect_id']) && isset($courseSubCatSelected['textbooks'][$selectedTextbookArr['connect_id']]['display_flag']))
5080                    ? $courseSubCatSelected['textbooks'][$selectedTextbookArr['connect_id']]['display_flag']
5081                    : 0;
5082                $result['user_preset_textbook_data']['textbook_type'] = $textbookOptionArr['textbook_type'];
5083                $result['userPresetDisplayFlg'] = $textbookOptionArr['userPresetDisplayFlg'] = $defaultTextbook['TextbookCategory']['display_flag'];
5084            } else {
5085                $textbookOptionArr['textbook_type'] = 2;
5086                $textbookOptionArr['defaulTextbook'] = "/HtmlTextbook/index?connect_id={$defaultConnectId}&html_dir={$defaultDir}&chapter_id={$defaultChapId}&isFromModal=1&emptyReservationTextbook=1";
5087                $textbookOptionArr['has_reservation_connect_id'] = false;
5088                $result['disable_button_flag'] = 1;
5089            }
5090        }
5091
5092        $textbookOptionArr['all'] = ($envFlag == 'reservation') ? false : true;
5093
5094        // - check if live reservation
5095        if ( $teacherId && $liveFlag ) {
5096            $this->Teacher->openDBReplica();
5097            $liveReservation = $this->Teacher->find('count', array(
5098                'conditions' => array(
5099                    'Teacher.id' => $teacherId,
5100                    'Teacher.live_lesson_flg' => 1,
5101                    'Teacher.status' => 1
5102                ),
5103                'recursive' => -1
5104            ));
5105            $this->Teacher->closeDBReplica();
5106
5107            if ($liveReservation) {
5108                // - disabled textbooks if live_lesson_flg is OFF
5109                if (isset($textbookLiveLessonFlg) && !$textbookLiveLessonFlg) {
5110                    $result['textbook_live_lesson_flg'] = true;
5111                }
5112                $textbookOptionArr['live_reservation'] = true;
5113            }
5114        }
5115
5116
5117        // NJ-33115 prepare bookmark data of new callan textbook
5118        if ($userId) {
5119            $bookmarkSeriesData = $this->LessonBookmark->getBookmarkData($userId, Configure::read('new_callan_textbook_category_id')[0]); // series bookmark
5120            $bookmarkCourseData = $this->LessonBookmark->getBookmarkData($userId, Configure::read('new_callan_textbook_category_id')[1]); // course bookmark
5121            
5122            $bookmarkSeries = json_decode($bookmarkSeriesData, true);
5123            $bookmarkCourse = json_decode($bookmarkCourseData, true);
5124            if (isset($bookmarkSeries['bookmark_id']) && !empty($bookmarkSeries['bookmark_id'])) {
5125                $textbookOptionArr['bookmark']['series'] = $bookmarkSeries;
5126            }
5127            
5128            if (isset($bookmarkCourse['bookmark_id']) && !empty($bookmarkCourse['bookmark_id'])) {
5129                $textbookOptionArr['bookmark']['course'] = $bookmarkCourse;
5130            }
5131        }
5132
5133        //set flag for hide counselor textbook
5134        $textbookOptionArr['hide_counselor_info'] = $hideCouselorFromMember;
5135        $textbookOptionArr['favorites'] = isset($allBook['favorites']) ? $allBook['favorites'] : false;
5136        $textbookOptionArr['liveFlag'] = $liveFlag;
5137
5138        if (isset($this->request->data['textbook_level']) && !empty($this->request->data['textbook_level'])) {
5139            $textbookOptionArr['textbook_level'] = $this->request->data['textbook_level'];
5140            $result['option'] = $view->element('textbook_category_selection',array(
5141                'courseArr' => isset($textbookOptionArr['courseArr']) ? $textbookOptionArr['courseArr'] : false,
5142                'seriesArr' => isset($textbookOptionArr['seriesArr']) ? $textbookOptionArr['seriesArr'] : false,
5143                'favorites' => isset($textbookOptionArr['favorites']) ? $textbookOptionArr['favorites'] : false,
5144                'liveFlag' => $liveFlag
5145            ));
5146            $result['levelFiltered'] = true;
5147        } else {
5148            $result['option'] = $view->element('modal_textbook_selection_2',array('optionArr' => $textbookOptionArr));
5149            $result['levelFiltered'] = false;
5150        }
5151        
5152        // - set result
5153        $result['textbook_default'] = $textbookOptionArr['defaulTextbook'];
5154        $result['textbook_type'] = $textbookOptionArr['textbook_type'];
5155        $result['reservation_flag'] = $defaultTextbook['TextbookCategory']['reservation_flg'] ?? 0;
5156        
5157        // - return json encoded data
5158        $this->response->type('json');
5159        $this->response->body(json_encode($result));
5160        return $this->response;
5161    }
5162
5163    /**
5164     * @api {post} /user/waiting/saveTexbook saveTextbookPreset()
5165     * @apiName saveTextbookPreset
5166     * @apiGroup Waiting
5167     * @apiDescription Saves the preset textbook for the authenticated user in Native Camp. It returns the status of the save operation and the details of the preset textbook.
5168     *
5169     * @apiBody {String} userId The ID of the user.
5170     * @apiBody {Object} presetParams The preset parameters.
5171     * @apiBody {Boolean} [is_pc_flg=true] Indicates if the request is from a PC.
5172     * @apiBody {String} [lang] The language code.
5173     * @apiBody {Boolean} [bypass_dummy_textbook_checker=true] Indicates if the dummy textbook checker should be bypassed.
5174     * 
5175     * @apiSuccess {Boolean} result Indicates whether the preset textbook was successfully saved.
5176     * @apiSuccess {String} image The image URL of the preset textbook.
5177     * @apiSuccess {String} name The name of the preset textbook.
5178     * @apiSuccess {String} cat_name The category name of the preset textbook.
5179     * @apiSuccess {String} chapter The chapter of the preset textbook.
5180     * @apiSuccess {Number} textbookCategoryTypeId The category type ID of the preset textbook.
5181     *
5182     * @apiSuccessExample {json} Success-Response:
5183     *     {
5184     *         "result": true,
5185     *         "image": "http://example.com/image.jpg",
5186     *         "name": "Textbook Name",
5187     *         "cat_name": "Category Name",
5188     *         "chapter": "Chapter 1",
5189     *         "textbookCategoryTypeId": 1
5190     *     }
5191     *
5192     * @apiError {String} status The status of the request (NG).
5193     * @apiError {String} message The error message.
5194     *
5195     * @apiErrorExample {json} Error-Response:
5196     *     {
5197     *         "status": "NG",
5198     *         "message": "Invalid request."
5199     *     }
5200     * 
5201     * @apiSampleRequest off
5202     */
5203    public function saveTextbookPreset($params = array()) {
5204        $status = false;
5205        $reservation_flg = 0;
5206        $this->autoRender = false;
5207
5208        // set preset params
5209        $presetParams = array(
5210            'is_pc_flg' => true,
5211            'lang' => $this->localizeDir,
5212            'bypass_dummy_textbook_checker'    => true
5213        );
5214
5215        if ($this->request->is('ajax')) {
5216            $data = $this->request->data;
5217
5218            // NJ-5836 set additional preset params
5219            $data['presetParams'] = $presetParams;
5220
5221            //if save succesful get the reservation flg of the textbook
5222            if ($this->UsersLastViewedTextbook->savePresetTextbook($data)) {
5223                $status = true;
5224            }
5225
5226            // 8020
5227            $presetParams = array("user_id" => $data['userId'] ?? null);
5228
5229            //add additional parameter in fetching preset textbook
5230            if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
5231                $presetParams["lang"] = $this->localizeDir;
5232            }
5233
5234            // check if user is valid for Study Sapuri Business English Daily textbooks
5235            if ((isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) &&
5236                ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
5237              ){
5238                $presetParams['userValidForSSBEDT'] = true;
5239            }
5240
5241            //fetch preset
5242            $textbookConnectId = $this->UsersLastViewedTextbook->getPresetTextbook($presetParams);
5243
5244        // request is POST
5245        } else {
5246            $data = $params;
5247
5248            // NJ-5836 set additional preset params
5249            $data['presetParams'] = $presetParams;
5250
5251            //if save succesful get the reservation flg of the textbook
5252            if ($this->UsersLastViewedTextbook->savePresetTextbook($data)) {
5253                $status = true;
5254            }
5255
5256            // 8020
5257            $presetParams = array("user_id" => $data['userId']);
5258
5259            //add additional parameter in fetching preset textbook
5260            if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
5261                $presetParams["lang"] = $this->localizeDir;
5262            }
5263
5264            // check if user is valid for Study Sapuri Business English Daily textbooks
5265            if (
5266                (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) &&
5267                ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
5268            ){
5269                $presetParams['userValidForSSBEDT'] = true;
5270            }
5271
5272            //fetch preset
5273            $textbookConnectId = $this->UsersLastViewedTextbook->getPresetTextbook($presetParams);
5274        }
5275        echo json_encode(array(
5276                'result' => $status,
5277                'image' => $textbookConnectId['image'] ?? '',
5278                'name' => $textbookConnectId['name'] ?? '',
5279                'cat_name' => $textbookConnectId['cat_name'] ?? '',
5280                'chapter' => $textbookConnectId['chapter'] ?? '',
5281                'textbookCategoryTypeId' => $textbookConnectId['textbook_info']['TextbookCategory']['type_id'] ?? 0,
5282        ));
5283        return;
5284    }
5285
5286    /**
5287     * @api {get} /user/:language/waiting/callLessonAlertandStartButton callLessonAlertandStartButton()
5288     * @apiName callLessonAlertandStartButton
5289     * @apiGroup Waiting
5290     * @apiDescription Retrieves the lesson alert and start button information for the authenticated user in Native Camp. It returns various information about the lesson status, user eligibility, and more.
5291     *
5292     * @apiParam {String} language The language code for the page.
5293     * 
5294     * @apiBody {String} studentId The ID of the student.
5295     * @apiBody {String} teacherId The ID of the teacher.
5296     * @apiBody {Boolean} counselingFlg Indicates if the lesson is a counseling session.
5297     * @apiBody {Boolean} [emergencyFlg=false] Indicates if the lesson is an emergency lesson.
5298     * @apiBody {Boolean} [isSpViewer=false] Indicates if the viewer is using a special viewer.
5299     * @apiBody {Boolean} [redLamp=false] Indicates if the red lamp is on.
5300     * 
5301     * @apiSuccess {Object} result The result object.
5302     * @apiSuccess {String} result.lesson_alert The HTML content for the lesson alert.
5303     * @apiSuccess {String} result.lesson_start_button The HTML content for the lesson start button.
5304     * @apiSuccess {Number} result.isReserved Indicates if the lesson is reserved (1: Yes, 0: No).
5305     * @apiSuccess {Number} result.unverifiedSMS Indicates if the SMS verification is unverified (1: Yes, 0: No).
5306     * @apiSuccess {Number} result.lessonStartIsNormalLitePLan Indicates if the user is on a normal lite plan (1: Yes, 0: No).
5307     * @apiSuccess {Number} result.studentDelayInSeconds The delay in seconds for the student lesson priority.
5308     *
5309     * @apiSuccessExample {json} Success-Response:
5310     *     {
5311     *         "lesson_alert": "<div>Lesson Alert Content</div>",
5312     *         "lesson_start_button": "<button>Start Lesson</button>",
5313     *         "isReserved": 1,
5314     *         "unverifiedSMS": 0,
5315     *         "lessonStartIsNormalLitePLan": 1,
5316     *         "studentDelayInSeconds": 3000
5317     *     }
5318     *
5319     * @apiError {String} status The status of the request (NG).
5320     * @apiError {String} message The error message.
5321     *
5322     * @apiErrorExample {json} Error-Response:
5323     *     {
5324     *         "status": "NG",
5325     *         "message": "Invalid request."
5326     *     }
5327     * 
5328     * @apiSampleRequest off
5329     */
5330    public function callLessonAlertandStartButton() {
5331        $this->autoRender = false;
5332        $view = new View($this, false);
5333        $get = $this->request->query;
5334        $lessonType = false;
5335        $displayFamilyAlert = false;
5336        $isSpViewer = !empty($get['isSpViewer']) ? 1: 0;
5337        $showTakeBusinessTestModal = false;
5338
5339        // check if teacher and student id exists
5340        if (
5341            !isset($get['studentId']) &&
5342            !isset($get['teacherId']) &&
5343            !isset($get['counselingFlg'])
5344        ) {
5345            throw new Exception("Invalid parameters!");
5346        }
5347
5348        // set vars
5349        $device = false;
5350        $ua = (!empty(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']))) ? myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) : '';
5351        $studentId = $get['studentId'];
5352        $teacherId = $get['teacherId'];
5353        $counselingFlg = $get['counselingFlg'];
5354        $isEmergencyLesson = (isset($get['emergencyFlg']) && $get['emergencyFlg']) ? true : false;
5355        $isGuestViwer = empty($studentId) ? 1 : 0;
5356        $isMobileView = $this->RequestHandler->isMobile();
5357
5358        $isRedLamp = isset($get['redLamp']) && $get['redLamp'] == "1" ? true : false;
5359        // get the data
5360        $teacherData = $this->Teacher->find('first', array(
5361            'fields' => array(
5362                'Teacher.home_flg',
5363                'Teacher.avatar_flg',
5364                'Teacher.avatar_parent_flg',
5365                'Teacher.avatar_id',
5366                'Teacher.native_speaker_flg',
5367            ),
5368            'conditions' => array(
5369                'Teacher.id' => $teacherId
5370            ),
5371            'recursive' => -1
5372        ));
5373
5374        // NJ-48797
5375        $isAvatarTeacher = isset($teacherData['Teacher']['avatar_flg']) && $teacherData['Teacher']['avatar_flg'] == 1;
5376
5377        if ($isAvatarTeacher) {
5378            $avatarParentFlg = isset($teacherData['Teacher']['avatar_parent_flg']) && $teacherData['Teacher']['avatar_parent_flg'] == 1;
5379        
5380            if (!$avatarParentFlg) {
5381                $getParentAvatarTeacher = $this->Teacher->find('first', array(
5382                    'fields' => array('Teacher.id', 'Teacher.native_speaker_flg'),
5383                    'conditions' => array(
5384                        'Teacher.id' => $teacherData['Teacher']['avatar_id'],
5385                        'Teacher.avatar_parent_flg' => 1
5386                    ),
5387                    'recursive' => -1
5388                ));
5389            } else {
5390                $getParentAvatarTeacher = $teacherData;
5391            }
5392        }
5393
5394        $param = array(
5395            'homeFlag' => isset($teacherData['Teacher']['home_flg']) ? $teacherData['Teacher']['home_flg'] : null,
5396            'isGuestViwer' => $isGuestViwer
5397        );
5398
5399        $canLesson = LessonOnairTable::canLesson($teacherId, $studentId, $param);
5400
5401        $liveData = isset($canLesson['liveLessonDetail']) && !empty($canLesson['liveLessonDetail']) ? $canLesson['liveLessonDetail'] : [];
5402        $hasRemainingLife = false;
5403
5404        if (
5405            $liveData &&
5406            $liveData['lesson_started'] &&
5407            !$liveData['lesson_finish'] &&
5408            !$isSpViewer &&
5409            !$isGuestViwer &&
5410            !$isMobileView
5411        ) {
5412
5413            // if api token is not set
5414            if (empty($this->sharedUserData['User']['api_token'])) {
5415
5416                $userApiToken = $this->User->generateAndSaveApiToken($studentId);
5417
5418                // update auth value
5419                $this->Session->write('Auth.User.api_token', $userApiToken);
5420            }
5421
5422            // open tunnel
5423            myTools::initializeApiTunnel(array('ChivoxTrainingController'));
5424
5425            // initialize controller
5426            $ctc = new ChivoxTrainingController();
5427
5428            // set data
5429            $ctc->params = [
5430                'nc_terminal_type' => 1, // pc
5431                'users_api_token' => $this->Auth->user('api_token'),
5432                'is_live_lesson' => 1,
5433                'chat_hash' => isset($liveData['chat_hash']) ? $liveData['chat_hash'] : null
5434            ];
5435
5436            // get remaining life details
5437            $noRemainingLifeDetails = json_decode($ctc->trainings_life_status(), true);
5438
5439            if (isset($noRemainingLifeDetails['error'])) {
5440                throw new Exception($noRemainingLifeDetails['error']['message']);
5441            }
5442
5443            $hasRemainingLife = ($noRemainingLifeDetails['infinite_life_flg'] || $noRemainingLifeDetails['remaining_life'] > 0 || $liveData['lesson_joined']) ? true : false;
5444        }
5445
5446        // check user agent
5447        if (strpos($ua, 'Silk') !== false) {
5448            $device = 'kindle';
5449        } else if (strpos($ua, 'Android') !== false) {
5450            $device = 'andriod';
5451        } else if (strpos($ua, 'iPhone') !== false) {
5452            $device = 'ios';
5453        } else if (strpos($ua, 'iPad') !== false) {
5454            $device = 'ios';
5455        } else if (strpos($ua, 'iPod') !== false) {
5456            $device = 'ios';
5457        } else {
5458            $device = 'pc';
5459        }
5460
5461        //check browser
5462        $unsupportedBorwser = false;
5463        $browser =  $this->request->header('User-Agent');
5464        if (preg_match('/(Edg|Edge)/i',$browser) ) {
5465            $unsupportedBorwser = false;
5466        } elseif (preg_match('/(OPR)/i',$browser)) {
5467            $unsupportedBorwser = true;
5468        } elseif (preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
5469            $unsupportedBorwser = false;
5470        } else if ( 
5471            $isSpViewer
5472            && preg_match('/(iPhone|iPad|iPod|Mozilla)/i',$browser)
5473            && preg_match('/(CriOS|FxiOS)/i',$browser)
5474        ) {
5475            //-- IOS CHROME
5476            $unsupportedBorwser = false;
5477        } else {
5478            $unsupportedBorwser = true;
5479        }
5480
5481        // get the teacher's current status
5482        $queryCondition = array(
5483            'fields' => array(
5484                    'TeacherRankCoin.coins',
5485                    'LessonOnair.id',
5486                    'LessonOnair.teacher_id',
5487                    'LessonOnair.user_id',
5488                    'LessonOnair.lesson_type',
5489                    'LessonOnair.live_lesson_flg'
5490                ),
5491            'joins' => array(
5492                array(
5493                    'type' => 'LEFT',
5494                    'table' => 'teacher_rank_coins',
5495                    'alias' => 'TeacherRankCoin',
5496                    'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
5497                )
5498            ),
5499            'conditions' => array(
5500                array('Teacher.id' => $teacherId)
5501            ),
5502            'show' => 'first'
5503        );
5504        $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
5505
5506        if ($isEmergencyLesson && $this->isStudySapuriTosUser) {
5507            $nextEmergencySlot = $this->LessonSchedule->getEmergencyTimeSlot();
5508            $nextReserveSlot = $this->LessonSchedule->getNextReservationTimeSlot();
5509            $queryCondition['fields'][] = "(
5510                ((select smb.id from shift_work_meal_breaks as smb where smb.lesson_time >= '{$nextReserveSlot['start']}' and smb.lesson_time <= '{$nextReserveSlot['end']}' and smb.teacher_id = Teacher.id limit 1) IS NULL) AND 
5511                ((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextEmergencySlot['start']}' and rs.lesson_time <= '{$nextEmergencySlot['end']}' and rs.status = 1 and rs.teacher_id = Teacher.id limit 1) IS NULL)
5512                ) as can_emergency_lesson";
5513            $queryCondition['fields'][] = "((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextReserveSlot['start']}' and rs.lesson_time <= '{$nextReserveSlot['end']}' and rs.status = 1 and rs.user_id = {$studentId} limit 1) IS NULL) 
5514                as student_no_next_reservation";
5515        }
5516
5517        $commonTeacherStatusParams = array(
5518            'page_display' => 'listTeacher',
5519            'query_conditions' => $queryCondition
5520        );
5521        $lessonOnair = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
5522
5523        $teacherStatusStandByDurationFieldStr = '(CASE when TeacherStatus.status = 2 then (TIME_TO_SEC(TIMEDIFF(NOW(), TeacherStatus.created))) else 0 end) as teacher_status_standby_duration';
5524        // teacher_status if login or break
5525        $teacherStatus1 = $this->TeacherStatus->find('first', array(
5526            'fields' => array(
5527                'TeacherStatus.status',
5528                'TeacherStatus.remarks1',
5529                'TeacherStatus.remarks2',
5530                $teacherStatusStandByDurationFieldStr
5531            ),
5532            'conditions' => array('TeacherStatus.teacher_id' => $teacherId)
5533        ));
5534        
5535        $isNotAvatar = isset($lessonOnair['Teacher']['avatar_flg']) && $lessonOnair['Teacher']['avatar_flg'] == 1 ? 0 : 1; // set to FALSE/0 if teacher is avatar
5536         $isNotCounselor = isset($lessonOnair['Teacher']['counseling_flg']) && $lessonOnair['Teacher']['counseling_flg'] == 1 ? 0 : 1; // set to FALSE/0 if teacher is avatar
5537
5538        $studentRemainingSecondsDelay = 0;
5539        if( $isNotAvatar && $isNotCounselor ) {
5540            if( isset($teacherStatus1[0]['teacher_status_standby_duration']) && $teacherStatus1[0]['teacher_status_standby_duration'] ) {
5541                if( (int)$teacherStatus1[0]['teacher_status_standby_duration'] <= (int)$this->studentLessonPriorityTimeDelayInSeconds ) {
5542                    $studentRemainingSecondsDelay = (int)$this->studentLessonPriorityTimeDelayInSeconds - (int)$teacherStatus1[0]['teacher_status_standby_duration'];
5543                }
5544            }
5545        }
5546
5547        // check if lessonOnair is empty
5548        if (isset($lessonOnair['LessonOnair'])) {
5549            $tmp = (object) $lessonOnair['LessonOnair'];
5550            if (!$tmp->id) {
5551                $lessonOnair['LessonOnair'] = null;
5552            }
5553        }
5554
5555        // pass onairs data
5556        $onair = $lessonOnair['LessonOnair'] ?? [];
5557
5558        // check if lessonOnair contains empty values
5559        if (!empty($onair)) {
5560            $oOnair = new LessonOnairTable($onair);
5561        }
5562
5563        // set onair
5564        if (!empty($teacherStatus1) && empty($onair)) {
5565            $oOnair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
5566        }
5567
5568        // if teacher status is '4', disable lesson
5569        if (
5570            isset($teacherStatus1['TeacherStatus']['status']) &&
5571            isset($canLesson['lessonAvailable']) &&
5572            $teacherStatus1['TeacherStatus']['status'] == 4
5573        ) {
5574            $canLesson['lessonAvailable'] = 0;
5575        }
5576
5577        // normal
5578        $resEndTime1 = 25;
5579        $resEndTime2 = 55;
5580        if ( isset($lessonOnair['Teacher']['avatar_flg']) && $lessonOnair['Teacher']['avatar_flg'] == 1 ) {
5581            $resEndTime1 = 19;
5582            $resEndTime2 = 49;
5583            // check if has upcoming reservation
5584            if (
5585                isset($canLesson['nextReservation']) &&
5586                $canLesson['nextReservation'] &&
5587                ((date("i") <= 29 && date("i") >= $resEndTime1) || (date("i") <= 59 && date("i") >= $resEndTime2)) &&
5588                isset($oOnair->status) &&
5589                isset($oOnair->connect_flg) &&
5590                $oOnair->connect_flg = 1
5591            ) {
5592                $canLesson['lessonAvailable'] = 0;
5593            }
5594
5595        }
5596
5597        // check if has upcoming reservation
5598        if (
5599            isset($canLesson['nextReservation']) &&
5600            $canLesson['nextReservation'] &&
5601            ((date("i") <= 29 && date("i") >= $resEndTime1) || (date("i") <= 59 && date("i") >= $resEndTime2)) &&
5602            isset($oOnair->status) &&
5603            isset($oOnair->connect_flg) &&
5604            $oOnair->connect_flg = 1
5605        ) {
5606            $oOnair->status = 2;
5607        }
5608
5609        //get preset textbook or last viewed
5610        $presetParams = array("user_id" => $get['studentId'], 'userValidForSSBEDT' => $this->userValidForSSBEDT());
5611
5612        //add additional parameter in fetching preset textbook
5613        if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
5614            $presetParams["lang"] = $this->localizeDir;
5615        }
5616
5617        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
5618        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
5619            # for preset
5620            $presetParams['connect_id'] = $preset_data['preset_connect_id'];
5621            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
5622
5623        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
5624            # use last viewed textbook if no preset data.
5625            $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
5626            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
5627        }
5628
5629        // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
5630        $presetParams['is_pc_flg'] = 1;
5631
5632        # fetch preset
5633        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
5634        if(!$preset) {
5635            unset($presetParams['connect_id']);
5636            unset($presetParams['last_opened_date']);
5637            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
5638        }
5639
5640        $lessonData = $preset["textbook_info"] ?? null;
5641        $categoryId = $lessonData["TextbookCategory"]["id"] ?? null;
5642        $categoryTypeId = $lessonData["TextbookCategory"]["type_id"] ?? 0;
5643        $textbookId = $lessonData["Textbook"]["id"] ?? null;
5644        if( $categoryTypeId == 1 ) { // course
5645            $seriesId = $this->Textbook->getTextbookSeriesId(array( 'textbook_id' => $textbookId ));
5646        } else { // series
5647            $seriesId = $categoryId;
5648        }
5649
5650        // check teacher badge
5651        $checkBadge = $this->TeacherBadge->find("first", array(
5652                "conditions" => array(
5653                    "TeacherBadge.teacher_id" => $get['teacherId'],
5654                    "TeacherBadge.textbook_category_id" => $seriesId
5655                ),
5656                "fields" => array("TeacherBadge.id"),
5657                "recursive" => -1
5658            )
5659        );
5660
5661        $canLessonTextbook = false;
5662        if( $checkBadge || $counselingFlg) {
5663            $canLessonTextbook = true;
5664        }
5665
5666        //check if the preset textbook is doesn't have reserve_flg
5667        $textbookForReservationOnly = isset($preset['reservation_flg']) && !$counselingFlg ? $preset['reservation_flg'] : 0;
5668
5669        //get the textbook course / category
5670        $textbookCategoryName = isset($preset['name']) ? $preset['name'] : '' ;
5671
5672        //get next available schedule
5673        $lesson_time_stamp = floor(time() / (30 * 60)) * (30 * 60);
5674        if(isset($canLesson['nextReserve'])) {
5675            $nextSchedule = isset($canLesson['nextReserve']['start']) ? $canLesson['nextReserve']['start'] : null;
5676            $checkNextSchedule = $nextSchedule ? $this->ShiftWorkOn->checkDataExist($teacherId , $nextSchedule) : null;
5677            $checkScheduleCurrent = $this->ShiftWorkOn->checkDataExist( $teacherId , date('Y-m-d H:i:s',$lesson_time_stamp));
5678        }
5679
5680        //lesson type in lesson onair is reserved or there is a current reservation
5681        $this->LessonSchedule->recursive = 0;
5682        $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($studentId);
5683        $isReserved = ((isset($lessonOnair['LessonOnair']['lesson_type']) && $lessonOnair['LessonOnair']['lesson_type'] == 2)
5684                                        || $reservedLessonData && ($reservedLessonData['Teacher']['id'] == $teacherId)) ? true : false;
5685        $corporateIndividualUser = false;
5686        $lessonOrangeButtonRemaining = false;
5687        $showNativeSpeakerWarning = false;
5688        if ($this->Auth->User('id')) {
5689            $userOnairData = $this->LessonOnair->find('first', array(
5690                'conditions' => array(
5691                    'LessonOnair.user_id' => $this->Auth->User('id'),
5692                    'LessonOnair.status' => Configure::read("lesson.status.lesson")
5693                )
5694            ));
5695
5696            $userDuplicateLesson = false;
5697            $lessonOnOther = false;
5698            $userNotEligible = false;
5699            $uOnair = isset($userOnairData['LessonOnair']) ? $userOnairData['LessonOnair']: '';
5700
5701            if ($uOnair != null) {
5702                $uOOnair = new LessonOnairTable($uOnair);
5703                //check user duplicate lesson
5704                if ($uOOnair && $uOOnair->status == 3 && $uOOnair->user_id == $this->Auth->User('id') && $uOOnair->teacher_id != $teacherId) {
5705                    $userDuplicateLesson = true;
5706                    $lessonType = $uOOnair->lesson_type;
5707                }
5708                //check lesson on others
5709                if (isset($oOnair) && $oOnair && $oOnair->status == 3 && $oOnair->teacher_id == $teacherId && $oOnair->user_id != $studentId) {
5710                    $lessonOnOther = true;
5711                }
5712            }
5713
5714            //NC-6310 check user have reservation
5715            $nextReservation = LessonScheduleTable::getReservation(array(
5716                'LessonSchedule.teacher_id' => $teacherId,
5717                'LessonSchedule.user_id' =>  $this->sharedUserData['User']['id']
5718            ));
5719
5720            //check user if free or failed
5721            $user = $this->sharedUserData;
5722            $userTable = new UserTable($user['User']);
5723            $userAdminFlag = isset($user['User']['admin_flg']) ? $user['User']['admin_flg'] : '';
5724            $userFailFlag = isset($user['User']['fail_flg']) ? $user['User']['fail_flg'] : '';
5725            $userDoubleCheckFlag = isset($user['User']['double_check_flg']) ? $user['User']['double_check_flg']: '';
5726            $userCardCompany = isset($user['User']['card_company']) ? $user['User']['card_company']: '';
5727            $corporateUserFlg = isset($user['User']['corporate_id']) ? $user['User']['corporate_id'] : false;
5728
5729            // if corporate user
5730            if (isset($user['User']['corporate_id'])) {
5731                $corporateAdminPaymentMethod = $this->Corporate->getPaymentMethod($user['User']['corporate_id']);
5732                $corporateIndividualUser = $corporateAdminPaymentMethod == 1 ? true : false;
5733
5734                // NJ-3660: if 20th day onwards of the month, check if corporate user must take business test
5735                $corporateUserDate = time();
5736                $twentyPlusDayOfTheMonth = strtotime(date('Y-m-20'));
5737                $isTakenBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_flg'])) ? $user['User']['monthly_speaking_business_attended_flg'] : 0;
5738                $isMustTakeBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_must_flg'])) ? $user['User']['monthly_speaking_business_attended_must_flg'] : 0;
5739
5740                // if user has not yet taken the monthly test and must flag is 1
5741                // and not a reserved lesson and current date is 20+ of the month
5742                $showTakeBusinessTestModal = false;
5743                if (
5744                    ($isTakenBusinessTestFlg == 0 && $isMustTakeBusinessTestFlg == 1) &&
5745                    !$isReserved &&
5746                    (
5747                        $corporateUserDate >= $twentyPlusDayOfTheMonth ||
5748                        (
5749                            $userAdminFlag == 1 ||
5750                            (
5751                                isset($user["User"]["nickname"]) &&
5752                                strpos(strtoupper($user["User"]["nickname"]), '%%%TEST%%%') !== false
5753                            )
5754                        )
5755                    )
5756                ) {
5757                    $showTakeBusinessTestModal = true;
5758                }
5759            }
5760
5761            // NC-5409 : Corporate Limited Plan
5762            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
5763            if ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.limited') ) {
5764
5765                // check if legible
5766                if (( ($corporateType == Configure::read('corporate_type.limited') && !$isReserved) || (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
5767                        $userDuplicateLesson || $unsupportedBorwser ||
5768                        $lessonOnOther
5769                ) && $studentId) {
5770                    $userNotEligible = true;
5771                }
5772
5773            } elseif ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.light') ) {
5774
5775                $corpLightCondition1 = (
5776                    ($corporateType == Configure::read('corporate_type.light') && !$isReserved) ||
5777                    (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
5778                    $userDuplicateLesson ||
5779                    $unsupportedBorwser ||
5780                    $lessonOnOther
5781                );
5782                // check if legible
5783                if ( $corpLightCondition1 && $studentId) {
5784                    $userNotEligible = true;
5785                }
5786            } elseif (
5787                (
5788                    isset($lessonOnair['Teacher']['native_speaker_flg']) &&
5789                    $lessonOnair['Teacher']['native_speaker_flg']
5790                ) &&
5791                (
5792                    $user['User']['native_option'] == null ||
5793                    $user['User']['native_option'] == 0
5794                ) &&
5795                !$isReserved &&
5796                !$tmp->live_lesson_flg &&
5797                !$this->isStudySapuriTosUser
5798            ) {
5799                $userNotEligible = true;
5800                $showNativeSpeakerWarning = true;
5801            } elseif ( // NJ-48797
5802                (isset($getParentAvatarTeacher['Teacher']['native_speaker_flg']) && $getParentAvatarTeacher['Teacher']['native_speaker_flg']) &&
5803                ($user['User']['native_option'] == null || $user['User']['native_option'] == 0) && 
5804                !$isReserved &&
5805                !$tmp->live_lesson_flg &&
5806                !$this->isStudySapuriTosUser
5807            ) {
5808                $showNativeSpeakerWarning = true;
5809                $userNotEligible = true;
5810            } else {
5811                // check if legible
5812                if (((!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
5813                        $userDuplicateLesson || $unsupportedBorwser || (!$userAdminFlag && ($userFailFlag == 1 || $userDoubleCheckFlag == 2)) ||
5814                        $lessonOnOther
5815                ) && $studentId) {
5816                    $userNotEligible = true;
5817                }
5818            }
5819            
5820            // show orange button
5821            $lessonOrangeButtonRemaining = $this->triggerOrangeButton($this->Auth->User('id'), $teacherId, $userNotEligible, $unsupportedBorwser, $canLesson['lessonAvailable'] ?? null);
5822
5823            # - [NJ-18003] conditions for terminate reserved lesson for sudden lesson
5824            $isReservedCanSuddenLesson = false;
5825            $isReservedCanLessonViewing = false;
5826            if (
5827                $canLessonTextbook &&             # - can lesson with the textbook
5828                !$textbookForReservationOnly && # - textbook not for reserve only
5829                !$unsupportedBorwser &&         # - supported browser
5830                $userDuplicateLesson &&         # - has lesson with other teacher
5831                $lessonType == Configure::read('lesson.type.reservation') &&
5832                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
5833                !$this->isStudySapuriUser &&    # - not sapuri user
5834                ($uOnair && $uOnair['leave_lesson']) && # - already left the reserved lesson
5835                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
5836                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
5837            ) {
5838                $isReservedCanSuddenLesson = true;
5839            }
5840
5841            if (
5842                !$this->isStudySapuriUser &&
5843                $lessonType == Configure::read('lesson.type.reservation') &&
5844                ($uOnair && $uOnair['leave_lesson']) # - already left the reserved lesson
5845            ) {
5846                $isReservedCanLessonViewing = true;
5847            }
5848            
5849            $canMidwayLesson = false;
5850            if (
5851                $canLessonTextbook &&             # - can lesson with the textbook
5852                !$textbookForReservationOnly && # - textbook not for reserve only
5853                !$unsupportedBorwser &&         # - supported browser
5854                $userDuplicateLesson &&         # - has lesson with other teacher
5855                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
5856                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
5857                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
5858            ) {
5859                $canMidwayLesson = true;
5860            }
5861        }
5862
5863        // NC-3755
5864        if (
5865            isset($this->sharedUserData['User']['parent_id']) &&
5866            !is_null($this->sharedUserData['User']['parent_id'])
5867        ) {
5868            $parent = $this->User->find('first', array(
5869                'fields' => array(
5870                    'User.id',
5871                    'User.hash16',
5872                    'User.charge_flg'
5873                ),
5874                'conditions' => array(
5875                    'User.id' => $this->sharedUserData['User']['parent_id']
5876                ),
5877                'recursive' => -1
5878            ));
5879
5880            if ($parent && $parent['User']['charge_flg'] != 1) {
5881                $displayFamilyAlert = true;
5882            }
5883        }
5884        // NC-4544 - check phone verification auth
5885        $verifyCount = $this->PhoneVerifyCheckLog->find('count',array(
5886            'conditions' => array(
5887                'user_id' => $this->Auth->User('id'),
5888                'status' => 0
5889            )
5890        ));
5891
5892
5893        $teacherParams = array(
5894            'type' => 'first',
5895            'args' => array(
5896                'conditions' => array(
5897                    'id' => $teacherId
5898                ),
5899                'recursive' => -1
5900            )
5901        );
5902        $teacherInfo = $this->Teacher->getTeachers($teacherParams);
5903
5904        // set localize url
5905        if (
5906            isset($get['la']) && in_array($get['la'], array_flip(Configure::read('pc_allowed_currencies'))) &&
5907            $get['la'] != Configure::read('default.user_language')
5908        ) {
5909            $localizeUrl = myTools::getUrl() . '/' . $get['la'];
5910        } else {
5911            $localizeUrl = myTools::getUrl();
5912        }
5913
5914        $corporateTypes = Configure::read('corporate_type_arr');
5915        // get live lesson coin
5916        $live_lesson_coin = 0;
5917        if (isset($teacherInfo['Teacher']['current_rank_id']) && $teacherInfo['Teacher']['current_rank_id']) {
5918             $live_lesson_coin = $this->LessonOnairsViewer->getLiveLessonCoinPrice(array(
5919                 'current_rank_id' => $teacherInfo['Teacher']['current_rank_id']
5920             ));
5921         }
5922
5923        # -don't check lesson daily limit if sapuri toS
5924        if (!$this->isStudySapuriTosUser) {
5925            // # NJ-3319
5926            $teacherStudentConnection = $this->TeacherStudentConnection->find('first', array(
5927                'conditions' => array(
5928                    'user_id' => $this->Auth->User('id'),
5929                    'teacher_id' => $teacherId
5930                ),
5931                'fields' => array(
5932                    'daily_lesson_minutes',
5933                    'daily_lesson_last_update',
5934                    'teacher_id'
5935                ),
5936                'recursive' => -1
5937            ));
5938
5939            $teacherStudentData = isset($teacherStudentConnection['TeacherStudentConnection']) ? $teacherStudentConnection['TeacherStudentConnection'] : array();
5940            if (isset($teacherStudentData['daily_lesson_minutes']) && $teacherStudentData['daily_lesson_minutes']) {
5941                $exceedDailyLimit = $this->LessonOnair->lessonStartButton(array(
5942                    'teacher_id' => $teacherId,
5943                    'teacherStudentData' => $teacherStudentData,
5944                    'counseling_flg' => isset($lessonOnair['Teacher']['counseling_flg']) ? $lessonOnair['Teacher']['counseling_flg'] : 0,
5945                    'avatar_flg' => isset($lessonOnair['Teacher']['avatar_flg']) ? $lessonOnair['Teacher']['avatar_flg'] : 0,
5946                    'nickname' => $userTable->nickname,
5947                    'admin_flg' => $userTable->admin_flg,
5948                    'isReserved' => $isReserved,
5949                    'type' => 1
5950                ));
5951            }
5952        }
5953
5954        $resetTimeLocal = TimezoneTable::computeTimeToUser(array(
5955            'time' => strtotime(date("Y-m-d 00:00:00")),
5956            'timestamp' => $this->timeDiffSecond,
5957            'format' => 'H:i'
5958        ));
5959
5960        // NJ-51 : Set delay for student lesson priority group
5961        $studentLessonPriorityTimeDelay = 0;
5962        $studentDelayInSeconds = 0;
5963
5964        if( $isNotAvatar && $isNotCounselor ) {
5965            if( isset($oOnair) && $oOnair && $oOnair->status == 1 && $oOnair->user_id == null ) {
5966                $studentLessonPriorityTimeDelay = $this->User->userPriorityDelay( array( 'user_id' => $this->Auth->user('id') ) );
5967                if( $studentLessonPriorityTimeDelay ){
5968                    $studentDelayInSeconds = (int) $studentLessonPriorityTimeDelay * 1000;
5969                }
5970            }
5971        }
5972
5973        $result['studentDelayInSeconds'] = $studentDelayInSeconds;
5974
5975        $hasOtherReserved = false;
5976        //- check if reservation is not by the current teacher
5977        if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
5978            $hasOtherReserved = true;
5979        }
5980
5981        $sapuriCoin = 0;
5982        if ($this->isStudySapuriUser) {
5983            $teacherParams = array(
5984                'teacher_id' => $teacherId,
5985                'current_rank_id' => $teacherInfo['Teacher']['current_rank_id']
5986            );
5987            $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
5988        }
5989
5990        # ~ check cannot emergency lesson
5991        $canEmergencyLesson = false;
5992        $emergencyBreakTime = ['status' => false];
5993        if (
5994            $isEmergencyLesson && 
5995            $this->isStudySapuriTosUser &&
5996            !$isReserved &&
5997            isset($lessonOnair[0]['can_emergency_lesson']) && 
5998            isset($lessonOnair[0]['student_no_next_reservation']) && 
5999            $lessonOnair[0]['can_emergency_lesson'] &&         # -can emergency
6000            $lessonOnair[0]['student_no_next_reservation']    # - no next reservation
6001        ) {
6002            $canEmergencyLesson = true;
6003        }
6004
6005        # ~if emergency lesson break time
6006        $currentMinutes = date("i");
6007        $currentHour = date("H");
6008        if ( $isEmergencyLesson && !$isReserved && (($currentMinutes >= 26 && $currentMinutes <= 29) || ($currentMinutes >= 56 && $currentMinutes <= 59))) {
6009            $canEmergencyLesson = false;
6010            $emergencyBreakTime['status'] = true;
6011            $emergencyBreakTime['time_span'] = '['.$currentHour.'時26分 ~ '.$currentHour.'時30分]['.$currentHour.'時56分 ~ '.$currentHour.'時00分]';
6012            $emergencyBreakTime['time_return'] = '['.$currentHour.'時30分]['.$currentHour.'時00分]';
6013        }
6014
6015        # ~no sudden lesson for sapuri toS user
6016        if ($this->isStudySapuriTosUser && !$isReserved) {
6017            $userNotEligible = true;
6018        }
6019
6020        $remainingLessonTime = 0;
6021        if( $isNotAvatar && $isNotCounselor && isset($oOnair->end_time)) {
6022            $remainingLessonTimeInSeconds = strtotime($oOnair->end_time)-strtotime('now');
6023            $remainingLessonTime = $remainingLessonTimeInSeconds <= 0 ? 0 : $remainingLessonTimeInSeconds;
6024        }
6025
6026    
6027        #NJ-18780: check for lite plan sudden lesson 
6028        // - check if reserved lesson
6029        $_userReservedNowLesson = ($reservedLessonData && $reservedLessonData['Teacher']['id'] == $teacherId) ? true : false;
6030
6031        $isNormalLitePlanUser = (in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan') ) ) ? true : false;
6032
6033        if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && !$_userReservedNowLesson && !$isEmergencyLesson) {
6034
6035            # disable the lesson button for lite plan if it is not reserved lesson
6036            $userNotEligible = true;
6037
6038            # add if reserve is still ongoing 
6039            if ($isReserved) {
6040                $userNotEligible =false;
6041            }
6042        }
6043
6044        // NJ-29831: check if user has reserved lesson for the next 5 min
6045        $scheduleReservationData = $this->LessonSchedule->getScheduledReservationNow($studentId, $teacherInfo['Teacher']['id'] ?? null);
6046        $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
6047        $hasLessonBeforeActualTime = false;
6048        if (isset($scheduleReservationData) && !empty($scheduleReservationData) && !$onGoingLesson) {
6049            $hasLessonBeforeActualTime = $isReserved = true;
6050        }
6051
6052        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
6053        $corporateTypeUserTable = myTools::getCoporateTypeUsingPaymentPlanId($userTable->payment_plan_id);
6054
6055        $redirectPlanUrl = '';
6056        $use7DaysTrialModal = false;
6057        $baseUrl = myTools::getUrl($this->localizeDir);
6058
6059        // if failed settlement -> paid or corporate individual (standard/premium)
6060        if (in_array($this->userMembershipType, Configure::read('membership_type_credit_retry'))) {
6061            $redirectPlanUrl = $baseUrl . '/payment/payment_credit_retry';
6062        // if free 
6063        } elseif ($this->userMembershipType == Configure::read('membership_type_plan_free')) {
6064            $redirectPlanUrl = $baseUrl . '/payment/payment_credit_charge';
6065        // if free (trial not yet conducted)
6066        } elseif ($this->userMembershipType == 13) {
6067            $userNotEligible = true;
6068            $use7DaysTrialModal = true;
6069        // if corporate company settlement failed -> standard/premium or
6070        } elseif (in_array($this->userMembershipType, Configure::read('membership_type_corporate_company_failed'))) {
6071            $redirectPlanUrl = $baseUrl . '/account/contract_information';
6072        }
6073
6074        $teacherLeaveNotice = '';
6075        $checkNextSchedule = isset($checkNextSchedule) ? $checkNextSchedule : false;
6076        $checkScheduleCurrent = isset($checkScheduleCurrent) ? $checkScheduleCurrent : false;
6077        $nextSchedule = isset($nextSchedule) ? $nextSchedule : '';
6078
6079        // NC-5554 : @modified. add trappings for meal break,
6080        // and change $canLesson['nextReserve']['start'] to mealbreak slot if has mealbreak
6081        if (
6082            (((isset($canLesson['lessonAvailable']) && $canLesson['lessonAvailable'])
6083            && !$checkNextSchedule 
6084            && $checkScheduleCurrent)
6085            || (isset($canLesson['hasMealbreakNext']) && $canLesson['hasMealbreakNext']))
6086            && !($teacherInfo['Teacher']['avatar_parent_flg'] == 1 || $teacherInfo['Teacher']['avatar_flg'] == 1)
6087            && !$isEmergencyLesson  # ~don't show in emergency page
6088            && !$this->isStudySapuriTosUser
6089            && $teacherInfo['Teacher']['home_flg'] != 1 // not home based teacher
6090            && isset($exceedDailyLimit) && !empty($exceedDailyLimit) 
6091        ) {
6092            $teacherLeaveNotice .= __d('waiting','こちらの講師は'). " ";
6093            $teacherLeaveNotice .= isset($nextSchedule) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReserve']['start']), 'timestamp' => $this->timeDiffSecond, 'format' => 'h:i')) : '';
6094            $teacherLeaveNotice .= " ". __d('waiting','までのレッスンとなりますので<br>ご了承ください。');
6095        }
6096
6097
6098        // NJ-56004 - if teacher is logged in and not on standby
6099        $isRedLamp = (isset($teacherStatus1['TeacherStatus']['status']) && $teacherStatus1['TeacherStatus']['status'] == 5) ? true : $isRedLamp;
6100
6101        $canDoLive = UserTable::canJoinLiveViewing($user['User']);
6102        if (
6103            $isReserved && 
6104            (
6105                $this->isStudySapuriUser || 
6106                $this->isStudySapuriTosUser || 
6107                in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')])
6108            )
6109        ) {
6110            $canDoLive = false;
6111        }
6112
6113
6114        // set view vars
6115        $data = array(
6116            'studentLessonPriorityTimeDelayInSeconds' => $studentLessonPriorityTimeDelay,
6117            'studentDelayInSeconds' => $studentDelayInSeconds,
6118            'studentRemainingSecondsDelay' => $studentRemainingSecondsDelay,
6119            'smsThroughFlg' => isset($userTable->sms_through_flg) ? $userTable->sms_through_flg : null,
6120            'verifyCount' => $verifyCount,
6121            'userFailFlag' => isset($userFailFlag)? $userFailFlag : 0,
6122            'userDoubleCheckFlag' => isset($userDoubleCheckFlag)? $userDoubleCheckFlag : 0,
6123            'userCardCompany' => isset($userCardCompany)? $userCardCompany : 0,
6124            'lessonOnOther' => isset($lessonOnOther)? $lessonOnOther : false,
6125            'unsupportedBorwser' => $unsupportedBorwser,
6126            'userDuplicateLesson' => isset($userDuplicateLesson)? $userDuplicateLesson : false,
6127            'lessonType' => $lessonType,
6128            'device' => $device,
6129            'canLesson' => $canLesson,
6130            'userId' => isset($studentId)? $studentId : '',
6131            'teacherId' => $teacherId,
6132            'teacherStatus' => $oOnair ?? [],
6133            'isRedLamp' => $isRedLamp,
6134            'statusCheck' => array(1, 4),
6135            'canLessonTextbook' => $canLessonTextbook,
6136            'isReserved' => $isReserved,
6137            'textbookForReservationOnly' => $textbookForReservationOnly,
6138            'textbookCategoryName' => $textbookCategoryName,
6139            'userNotEligible' => isset($userNotEligible)? $userNotEligible : false,
6140            'reservedLessonData' => $reservedLessonData,
6141            'corporateLimitedPlan' => (isset($corporateType) && $corporateType == Configure::read('corporate_type.limited') ) ,// corporate limited plan
6142            'corporateLightPlan' => (isset($corporateType) && $corporateType == Configure::read('corporate_type.light') ) ,// corporate light plan
6143            'corporateIndividualUser' => $corporateIndividualUser,
6144            'corporateUserFlg' => isset($corporateUserFlg) ? $corporateUserFlg : false,
6145            'corporatePlanName' => isset($corporateTypeUserTable) ? (isset($corporateTypes[$corporateTypeUserTable]) ? $corporateTypes[$corporateTypeUserTable] : '') : '',
6146            'lessonOrangeButtonRemaining' => $lessonOrangeButtonRemaining,
6147            'checkNextSchedule' => $checkNextSchedule,
6148            'nextSchedule' => $nextSchedule,
6149            'checkScheduleCurrent' => $checkScheduleCurrent,
6150            'displayFamilyAlert' => $displayFamilyAlert,
6151            'nextReservation' => isset($nextReservation) ? $nextReservation : '',
6152            'lessonOnair' => $lessonOnair,
6153            'teacherInfo' => $teacherInfo,
6154            'localizeUrl' => $localizeUrl,
6155            'showNativeSpeakerWarning' => $showNativeSpeakerWarning,
6156            'liveViewCoin' => $live_lesson_coin,
6157            'canDoLive' => $canDoLive,
6158            'points' => $this->UsersPoint->getCurrentUserPoint($userTable->id),
6159            'exceedDailyLimit' => isset($exceedDailyLimit) ? $exceedDailyLimit : false,
6160            'resetTimeLocal' => $resetTimeLocal == "00:00" ? "24:00" : $resetTimeLocal,
6161            'hasOtherReserved' => $hasOtherReserved,
6162            'showTakeBusinessTestModal' => $showTakeBusinessTestModal,
6163            'isEmergencyLessonPage' => $isEmergencyLesson,
6164            'canEmergencyLesson' => $canEmergencyLesson,
6165            'emergencyBreakTime' => $emergencyBreakTime,
6166            'sapuriCoin' => $sapuriCoin,
6167            'isReservedCanSuddenLesson' => $isReservedCanSuddenLesson ?? false,
6168            'isReservedCanLessonViewing' => $isReservedCanLessonViewing ?? false,
6169            'canMidwayLesson' => $canMidwayLesson ?? false,
6170            'remainingLessonTime' => $remainingLessonTime,
6171            'lessonEndTime' => isset($oOnair->end_time) ? $oOnair->end_time : '',
6172            'isGuestViwer' => $isGuestViwer,
6173            'isMobileView' => $isMobileView,
6174            'isSpViewer' => $isSpViewer,
6175            'lessonStartIsNormalLitePLan' => $isNormalLitePlanUser  ? 1 : 0,
6176            'dummyLessonRoom' => $hasLessonBeforeActualTime,
6177            'isCounselor' => (isset($teacherInfo['Teacher']['counseling_flg']) && $teacherInfo['Teacher']['counseling_flg']) ? true : false,
6178            'redirectPlanUrl' => $redirectPlanUrl,
6179            'use7DaysTrialModal' => $use7DaysTrialModal,
6180            'membershipType' => $this->userMembershipType,
6181            'teacherLeaveNotice' => $teacherLeaveNotice,
6182            'isStudySapuriTosUser' => $this->isStudySapuriUser,
6183            'hasRemainingLife' => $hasRemainingLife
6184        );
6185
6186        // load lesson alert
6187        $result['lesson_alert'] = $view->element('lesson_alert', $data);
6188
6189        // load lesson start button
6190        $result['lesson_start_button'] = $view->element('lesson_start_button', $data);
6191
6192        // reserved flag
6193        $result['isReserved'] = ($isReserved) ? 1 : 0;
6194        $result['unverifiedSMS'] = empty($verifyCount) && empty($userTable->sms_through_flg) ? 1 : 0;
6195
6196        //check if Lite User
6197        $result['lessonStartIsNormalLitePLan'] = $isNormalLitePlanUser ? 1 : 0;
6198
6199        // - set to json
6200        $this->response->type('json');
6201        $this->response->body(json_encode($result));
6202
6203        // return json data
6204        return $this->response;
6205    }
6206
6207    /**
6208     * @api {post} /user/waiting/loadMoreSelfReviews loadMoreSelfReviews()
6209     * @apiName loadMoreSelfReviews
6210     * @apiGroup Waiting
6211     * @apiDescription Loads more self-reviews for a specific teacher and user in Native Camp. It returns the list of self-reviews and indicates if there are more pages available.
6212     *
6213     * @apiBody {Number} [page=2] The page number to load (default is 2).
6214     * @apiBody {String} teacherId The ID of the teacher.
6215     * @apiBody {String} userId The ID of the user.
6216     * 
6217     * @apiSuccess {String} list The HTML list of self-reviews.
6218     * @apiSuccess {Boolean} hasNext Indicates whether there are more pages of self-reviews available.
6219     *
6220     * @apiSuccessExample {json} Success-Response:
6221     *     {
6222     *         "list": "<li>Review 1</li><li>Review 2</li>",
6223     *         "hasNext": true
6224     *     }
6225     *
6226     * @apiError {String} status The status of the request (NG).
6227     * @apiError {String} message The error message.
6228     *
6229     * @apiErrorExample {json} Error-Response:
6230     *     {
6231     *         "status": "NG",
6232     *         "message": "Invalid request."
6233     *     }
6234     * 
6235     * @apiSampleRequest off
6236     */
6237    public function loadMoreSelfReviews() {
6238        $this->autoRender = false;
6239        $list = '';
6240        if ($this->request->is('ajax')) {
6241            $page = isset($this->request->data['page']) ?  $this->request->data['page'] : 2;
6242          $teacherId = isset($this->request->data['teacherId']) ? $this->request->data['teacherId'] : 0;
6243          $userId = isset($this->request->data['userId']) ? $this->request->data['userId'] : 0;
6244            //reviews
6245      $selfReviews = $this->getUserReviews($userId, $teacherId, $page);
6246            $view = new View($this, false);
6247            $list = $view->element('self_comment_list', array('selfReviews' => $selfReviews));
6248        }
6249        return json_encode(
6250            array(
6251                'list' => $list,
6252                'hasNext' => $this->params['paging']['UsersClassEvaluation']['nextPage'] ?? false
6253            ));
6254    }
6255
6256    /**
6257    * get own user review count and reviews
6258    * @param int user_id
6259    */
6260    private function getUserReviews($userId, $teacherId, $page = 1) {
6261        $this->paginate = array(
6262            'fields' => array(
6263                'UsersClassEvaluation.id',
6264                'UsersClassEvaluation.rate',
6265                'UsersClassEvaluation.user_comment',
6266                'UsersClassEvaluation.created'
6267            ),
6268            'conditions' => array(
6269                    'UsersClassEvaluation.teacher_id' => $teacherId,
6270                    'UsersClassEvaluation.user_id' => $userId,
6271                    'UsersClassEvaluation.rate IS NOT NULL',
6272                ),
6273            'page' => $page,
6274            'limit' => $this->selfReviewLimit,
6275            'order' => 'UsersClassEvaluation.created DESC',
6276            'recursive' => -1
6277        );
6278        return $this->paginate('UsersClassEvaluation');
6279    }
6280
6281    //Retrieves the reservation and cancellation statistics for a specific teacher in Native Camp. It returns the count of reservations and cancellations for the current and previous month, as well as the cancellation rates.
6282    public function getReserveAndCancelled($teacherId) {
6283        //params
6284        $param = array('teacher_id' => $teacherId);
6285
6286        //get count finish reservation and cancelled reservations
6287        $thisMonthReservation = $this->LessonSchedule->getCurrentMonthReservationCount($param);
6288        $lastMonthReservation = $this->LessonSchedule->getLastMonthReservationCount($param);
6289        $thisMonthReservedCancellation = $this->LessonScheduleCancel->getCurrentReservationCancelledCount($param);
6290        $lastMonthReservedCancellation = $this->LessonScheduleCancel->getLastReservationCancelledCount($param);
6291
6292        //get divisors
6293        $lastMonth = strtotime("first day of previous month");
6294        $thisMonthLSDivisor = $this->LessonSchedule->getCancellationRateDivisor($teacherId);
6295        $lastMonthLSDivisor = $this->LessonSchedule->getCancellationRateDivisor($teacherId, $lastMonth);
6296        $thisMonthLSCDivisor = $this->LessonScheduleCancel->getCancellationRateDivisor($teacherId);
6297        $lastMonthLSCDivisor = $this->LessonScheduleCancel->getCancellationRateDivisor($teacherId, $lastMonth);
6298
6299        $thisMonthDivisor = $thisMonthReservation + $thisMonthLSDivisor + $thisMonthLSCDivisor;
6300        $lastMonthDivisor = $lastMonthReservation + $lastMonthLSDivisor + $lastMonthLSCDivisor;
6301
6302        $thisMonthCancellationPercentage = ($thisMonthDivisor == 0) ? 0 : (int)(($thisMonthReservedCancellation / $thisMonthDivisor) * 100);
6303        $lastMonthCancellationPercentage = ($lastMonthDivisor == 0) ? 0 : (int)(($lastMonthReservedCancellation / $lastMonthDivisor) * 100);
6304
6305        return array(
6306            'this_month_reserved' => $thisMonthReservation,
6307            'last_month_reserved' => $lastMonthReservation,
6308            'this_month_cancelled' => $thisMonthReservedCancellation,
6309            'last_month_cancelled' => $lastMonthReservedCancellation,
6310            'this_month_cancellation_rate' => $thisMonthCancellationPercentage,
6311            'last_month_cancellation_rate' => $lastMonthCancellationPercentage
6312        );
6313    }
6314
6315    /**
6316    * shows the orange button after the lesson end
6317    * @param int $userId
6318    * @param int $teacherId
6319    * @param boolean $userNotEligible
6320    * @param boolean $unsupportedBorwser
6321    * @param boolean $canLesson
6322    * @return int $lessonOrangeButtonRemaining
6323    ***/
6324    private function triggerOrangeButton($userId='', $teacherId='', $userNotEligible=false, $unsupportedBorwser=false, $canLesson=false) {
6325        $lessonOrangeButtonRemaining = false;
6326        $secondsRemaining = $this->LessonOnairsLog->getLastLessonSecondsRemaining($userId, $teacherId);
6327        if ($secondsRemaining && !$userNotEligible && !$unsupportedBorwser && $canLesson) {
6328            $lessonOrangeButtonRemaining = $secondsRemaining;
6329        }
6330        return $lessonOrangeButtonRemaining;
6331    }
6332
6333    /**
6334     * @api {post} /user/waiting/deleteLessonOnair deleteLessonOnair()
6335     * @apiName deleteLessonOnair
6336     * @apiGroup Waiting
6337     * @apiDescription Deletes the ongoing lesson on-air information for the authenticated user in Native Camp. It forcefully terminates the lesson if necessary.
6338     *
6339     * @apiBody {Number} [lesson_finish=6] The lesson finish status (default is 6 for force terminate).
6340     * 
6341     * @apiSuccess {Boolean} result Indicates whether the lesson on-air information was successfully deleted.
6342     *
6343     * @apiSuccessExample {json} Success-Response:
6344     *     {
6345     *         "result": true
6346     *     }
6347     *
6348     * @apiError {String} status The status of the request (NG).
6349     * @apiError {String} message The error message.
6350     *
6351     * @apiErrorExample {json} Error-Response:
6352     *     {
6353     *         "status": "NG",
6354     *         "message": "Invalid request."
6355     *     }
6356     * 
6357     * @apiSampleRequest off
6358     */
6359    public function deleteLessonOnair () {
6360        $this->autoRender = false;
6361
6362        // get lesson onair
6363        $lessonOnair = $this->LessonOnair->find('first', array(
6364            'fields' => array(
6365                'LessonOnair.id',
6366                'LessonOnair.lesson_type',
6367                'LessonOnair.leave_lesson'
6368            ),
6369            'conditions' => array(
6370                'LessonOnair.user_id' => $this->Auth->user('id')
6371            ),
6372            'recursive' => -1
6373        ));
6374
6375        // if don't have ongoing lesson onair information
6376        if (!$lessonOnair) {
6377            $this->log("[delete_lesson_onair] has no lesson onair", "debug");
6378            return;
6379        }
6380
6381        // if reserve lesson
6382        if (
6383            !empty($lessonOnair) && // if has lesson onair
6384            isset($lessonOnair['LessonOnair']['lesson_type']) && // if lesson type is set
6385            $lessonOnair['LessonOnair']['lesson_type'] == 2 // if lesson type is reserve lesson
6386        ) {
6387            // if not yet leave lesson -> force to leave lesson
6388            if ($lessonOnair['LessonOnair']['leave_lesson'] == 0) {
6389                $force_leave_lesson = LessonOnairTable::studentForceLeaveLesson(['lesson_onair_id' => $lessonOnair['LessonOnair']['id']]);
6390                
6391                if (!$force_leave_lesson) {
6392                    throw new Exception('error: Unable to forcefully terminate ongoing lesson ->' . json_encode($lessonOnair));
6393                }
6394            }
6395            // if not normal lesson
6396        } elseif (isset($lessonOnair["LessonOnair"]["lesson_type"]) && $lessonOnair["LessonOnair"]["lesson_type"] != 1) {
6397            throw new Exception('error: not a normal lesson ->' . json_encode($lessonOnair));
6398        }
6399
6400        // log
6401        $this->log("[delete_lesson_onair] deleting lesson onair -> " . json_encode($lessonOnair), "debug");
6402        
6403        $lesson_finish_status = !empty($this->request->data['lesson_finish']) ? $this->request->data['lesson_finish'] : 6; // set lesson finish status, or else set to 6 = force terminate default
6404
6405        // delete lesson oanir
6406        $res = LessonOnairTable::delete($lessonOnair['LessonOnair']['id'], array(), $lesson_finish_status);
6407        
6408        return json_encode(array('result' => $res ? true : false));
6409    }
6410
6411    /**
6412    * get online teachers first page
6413    */
6414    private function getTeacherOnlineList() {
6415        $returnData = array();
6416        $conditionArr = array();
6417        $conditionResult = $this->getSearchCondition();
6418        $conditionResult['conditions'] = array($conditionResult['conditions']);
6419
6420        $commonTeacherStatusParams = array(
6421            'page_display' => 'searchPage',
6422            'query_conditions' => $conditionResult
6423        );
6424        $data = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
6425        
6426        //clear teacher id
6427        $this->Session->delete('waiting-loadedTID');
6428        //save new teacher id
6429        if ($data) {
6430            $teacherId = array();
6431            foreach ($data['TeacherOnlineList'] as $teacher) {
6432                $teacherId[] = $teacher['Teacher']['id'];
6433            }
6434            $this->Session->write('waiting-loadedTID', $teacherId);
6435        }
6436        $returnData['teacherRecordCount'] = $data['teacherRecordCount'];
6437        $returnData['teacherData'] = $data['TeacherOnlineList'];
6438        $returnData['limitGauge'] = $conditionResult['limitGauge']+1;
6439        $returnData['limit'] = $conditionResult['limitCondition'];
6440        return $returnData;
6441    }
6442
6443    /**
6444    * get default search condition
6445    */
6446    private function getSearchCondition() {
6447        //default sort
6448        $sortCondition =  array(
6449            '(select if(count(*) > 0, 1, 0)
6450               FROM lesson_onairs
6451              WHERE teacher_id = Teacher.id AND status = 1 AND connect_flg = 1 LIMIT 1) desc',
6452
6453            '(if ((select if (count(*) > 0, 1, 0)
6454            from teacher_status
6455            where teacher_id = Teacher.id and status = 4 LIMIT 1)
6456
6457            OR
6458
6459            (select if (count(*) > 0, 1, 0)
6460            from lesson_onairs
6461            where teacher_id = Teacher.id and status <> 1 and connect_flg = 1 LIMIT 1), 3, 0)) desc',
6462
6463            'TeacherWeeklyRating.ratings desc',
6464
6465            'Teacher.lesson_count desc',
6466
6467            'Teacher.name asc'
6468        );
6469        //get block teachers id
6470        $blockList = BlockListTable::getBlocks($this->Auth->User('id'), false, 'all');
6471
6472        //default condition
6473        $conditions = array(
6474            'Teacher.id NOT IN' => $blockList,
6475            'Teacher.status' => 1,
6476            'Teacher.admin_flg' => 0,
6477            'Teacher.counseling_flg' => 0,
6478            'Teacher.last_login_time >=' => date('Y-m-d 00:00:00', strtotime('-59 days')),
6479            'LessonOnair.status = 1',
6480            'LessonOnair.connect_flg = 1'
6481        );
6482
6483        // NC-7031
6484        $conditions["AND"]["OR"] = array(
6485            array("Teacher.avatar_parent_flg" => 0, "Teacher.avatar_flg" => 0) // normal teacher
6486        );
6487        //stealth teacher
6488        if ($this->Cookie->read('stealth.setting') != 'on') {
6489            $conditions['Teacher.stealth_flg <>'] = 1;
6490        }
6491
6492        return array(
6493            'conditions' => $conditions,
6494            'sortCondition' => $sortCondition,
6495            'limitGauge' => 1,
6496            'pageLimit' => 80,
6497            'limitCondition' => 80,
6498            'defaultPageLimit' => 80,
6499            'seeMorePageLimit' => 18,
6500            'force_index' => 'FORCE INDEX(last_login_time)'
6501        );
6502    }
6503
6504    //not used function
6505    public function getApologyList($teacher_id = null) {
6506        $cancellesson = $this->LessonScheduleCancel->find('all', array(
6507            'conditions'=>array(
6508                'LessonScheduleCancel.user_id' => $this->Auth->user('id'),
6509                'LessonScheduleCancel.teacher_id' => $teacher_id,
6510#                'LessonScheduleCancel.lesson_time > ' => date('Y-m-d H:i:s'),
6511                'LessonScheduleCancel.status' => Configure::read('reserve_cancel_status_list'),//3 - admin cancel, 4 - system cancel, [24-28] - teacher cancellation, [29-33] - admin cancellation
6512                'LessonScheduleCancel.apology_show' => 1
6513            ),
6514            'fields' => array('LessonScheduleCancel.id', 'LessonScheduleCancel.lesson_time', 'LessonScheduleCancel.user_id','Teacher.id', 'Teacher.name'),
6515            'joins' => array(
6516                    array(
6517                        'type' => 'INNER',
6518                        'table' => 'teachers',
6519                        'alias' => 'Teacher',
6520                        'conditions' => array('Teacher.id = LessonScheduleCancel.teacher_id')
6521                        )
6522                ),
6523            'order' => 'LessonScheduleCancel.id desc'
6524        ));
6525
6526        return $cancellesson;
6527    }
6528
6529    /**
6530     * reservation limit
6531     * @return int
6532     * 1: warning 4th reservation
6533     * 2: 20 lesson reservation only
6534     * 3: 4 reservation only for each teacher
6535     * 4: cancellation limit
6536     * 5: complimentary plan
6537     * 6: corporate light max lesson limit
6538     * 7: lesson request max limit
6539     * 8: eligible for lesson request
6540     */ 
6541
6542     /**
6543     * @api {post} /user/waiting/limit-warning limitwarning()
6544     * @apiName limitwarning
6545     * @apiGroup Waiting
6546     * @apiDescription Checks for reservation limits and warnings for the authenticated user in Native Camp. It returns the status and any relevant messages or limits.
6547     *
6548     * @apiBody {String} [userId] The ID of the user (optional if fromCorporateManagement or fromSapuriTos is set).
6549     * @apiBody {Boolean} [fromCorporateManagement] Indicates if the request is from corporate management.
6550     * @apiBody {Boolean} [fromSapuriTos] Indicates if the request is from Sapuri TOS.
6551     * 
6552     * @apiSuccess {String} status The status of the request (OK or NG).
6553     * @apiSuccess {Number} content The content of the response.
6554     * @apiSuccess {Number} cancelCount The count of cancellations by the user.
6555     *
6556     * @apiSuccessExample {json} Success-Response:
6557     *     {
6558     *         "status": "OK",
6559     *         "content": 1,
6560     *         "cancelCount": 2
6561     *     }
6562     *
6563     * @apiError {String} status The status of the request (NG).
6564     * @apiError {Number} content The content of the response.
6565     * @apiError {Number} cancelCount The count of cancellations by the user.
6566     *
6567     * @apiErrorExample {json} Error-Response:
6568     *     {
6569     *         "status": "NG",
6570     *         "content": 0,
6571     *         "cancelCount": 0
6572     *     }
6573     * 
6574     * @apiSampleRequest off
6575     */
6576    public function limitwarning() {
6577        $this->autoRender = false;
6578
6579        if ($this->request->is('post')) {
6580            $post = $this->request->data;
6581
6582            // NC-8336
6583            if (
6584                isset($post['userId']) &&
6585                (isset($post['fromCorporateManagement']) || isset($post['fromSapuriTos']))
6586            ) {
6587                // nothing to do
6588            } else {
6589                $post['userId'] = $this->Auth->user('id');
6590                $post['user'] = $this->sharedUserData['User'];
6591            }
6592
6593            $post['nc_terminal_type'] = 1; // pc
6594            $post['timeDiffSecond'] = $this->timeDiffSecond;
6595 
6596            // open tunnel
6597            myTools::initializeApiTunnel(['ReservationController']);
6598
6599            // initialize controller
6600            $rc = new ReservationController();
6601
6602            // set data
6603            $rc->params = $post;
6604
6605            // process
6606            return $rc->limitWarning();
6607        } else {
6608            return json_encode([
6609                'status' => 'NG',
6610                'content' => 0,
6611                'cancelCount' => 0
6612            ]);
6613        }
6614    }
6615
6616    /**
6617     * @api {post} /user/waiting/updatedScheduleColor updatedScheduleColor()
6618     * @apiName updatedScheduleColor
6619     * @apiGroup Waiting
6620     * @apiDescription Retrieves the updated schedule color information for the authenticated user in Native Camp. It returns the dates when lessons are not available.
6621     *
6622     * @apiBody {String} teacherId The ID of the teacher.
6623     * 
6624     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
6625     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
6626     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
6627     *
6628     * @apiSuccessExample {json} Success-Response:
6629     *     {
6630     *         "disableAll": false,
6631     *         "disabledDays": [
6632     *             "2023-12-01",
6633     *             "2023-12-02"
6634     *         ]
6635     *     }
6636     *
6637     * @apiError {String} status The status of the request (NG).
6638     * @apiError {String} message The error message.
6639     *
6640     * @apiErrorExample {json} Error-Response:
6641     *     {
6642     *         "status": "NG",
6643     *         "message": "Invalid request."
6644     *     }
6645     * 
6646     * @apiSampleRequest off
6647     */
6648    public function updatedScheduleColor() {
6649        $this->autoRender = false;
6650        if ($this->request->is('ajax')) {
6651            $teacherId = $this->request->data['teacherId'];
6652
6653            // NJ-18780 : 
6654            $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
6655            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
6656
6657            $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
6658                'userId' => $this->Auth->user('id'),
6659                'teacherId' => $teacherId,
6660                'timeDiff' => $this->timeDiff,
6661                'isNormalLitePlanUser' => $isNormalLitePlanUser
6662            ));
6663            return json_encode($disabledSchedule);
6664        }
6665    }
6666
6667    /**
6668     * @api {post} /user/waiting/getAvatarDisabledDates getAvatarDisabledDates()
6669     * @apiName getAvatarDisabledDates
6670     * @apiGroup Waiting
6671     * @apiDescription Retrieves the disabled dates for avatar lessons for the authenticated user in Native Camp. It returns the dates when avatar lessons are not available.
6672     *
6673     * @apiBody {String} teacherId The ID of the avatar teacher.
6674     * 
6675     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
6676     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
6677     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
6678     *
6679     * @apiSuccessExample {json} Success-Response:
6680     *     {
6681     *         "disableAll": false,
6682     *         "disabledDays": [
6683     *             "2023-12-01",
6684     *             "2023-12-02"
6685     *         ]
6686     *     }
6687     *
6688     * @apiError {String} status The status of the request (NG).
6689     * @apiError {String} message The error message.
6690     *
6691     * @apiErrorExample {json} Error-Response:
6692     *     {
6693     *         "status": "NG",
6694     *         "message": "Invalid request."
6695     *     }
6696     * 
6697     * @apiSampleRequest off
6698     */
6699    public function getAvatarDisabledDates() {
6700        $this->autoRender = false;
6701        if ($this->request->is('ajax')) {
6702            $teacherId = $this->request->data['teacherId'];
6703            $getAvatarParams = array(
6704                "avatar_id" => $teacherId,
6705                "user_id" => $this->Auth->user('id'),
6706                "stealth_flg" => $this->Cookie->read('stealth.setting')
6707            );
6708
6709            // NJ-18780 : 
6710            $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
6711            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans'))) ? true : false;
6712
6713            $avatarTeacherIds = $this->Teacher->getAvatarTeacherId($getAvatarParams);
6714            $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
6715                'userId' => $this->Auth->user('id'),
6716                'teacherId' => $avatarTeacherIds,
6717                'timeDiff' => $this->timeDiff,
6718                'isNormalLitePlanUser' => $isNormalLitePlanUser
6719            ));
6720            return json_encode($disabledSchedule);
6721        }
6722    }
6723
6724    /**
6725     * @api {get} /user/sp/counselor_detail/ sp_counselor()
6726     * @apiName sp_counselor
6727     * @apiGroup Waiting
6728     * @apiDescription Redirects the user to the counselor detail page.
6729     *
6730     * @apiSuccess {String} url The URL to which the user is redirected.
6731     *
6732     * @apiSuccessExample {json} Success-Response:
6733     *     {
6734     *         "url": "https://example.com/user/counselor_detail"
6735     *     }
6736     *
6737     * @apiError {String} status The status of the request (NG).
6738     * @apiError {String} message The error message.
6739     *
6740     * @apiErrorExample {json} Error-Response:
6741     *     {
6742     *         "status": "NG",
6743     *         "message": "Invalid request."
6744     *     }
6745     * 
6746     * @apiSampleRequest off
6747     */
6748    public function sp_counselor() {
6749        return $this->redirect(myTools::getUrl() . '/user/counselor_detail', 301);
6750    }
6751
6752    /**
6753     * @api {get} /user/:language/counselor_detail counselor()
6754     * @apiName counselor
6755     * @apiGroup Waiting
6756     * @apiDescription Retrieves the counselor details for the authenticated user in Native Camp. It returns various information about the user's counselor status, lesson history, and more.
6757     *
6758     * @apiParam {String} language The language code for the page.
6759     * 
6760     * @apiSuccess {Object} teacher The counselor information.
6761     * @apiSuccess {String} teacher.id The ID of the counselor.
6762     * @apiSuccess {String} teacher.name The name of the counselor.
6763     * @apiSuccess {String} teacher.image_url The URL of the counselor's image.
6764     * @apiSuccess {Boolean} isFav Indicates whether the counselor is favorited by the user.
6765     * @apiSuccess {Object} teacherFavsColors The favorite colors for the counselor.
6766     * @apiSuccess {Number} favoriteCount The count of users who have favorited the counselor.
6767     * @apiSuccess {Boolean} isHide Indicates whether the counselor is hidden by the user.
6768     * @apiSuccess {Boolean} isLoggedIn Indicates whether the user is logged in.
6769     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
6770     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
6771     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
6772     * @apiSuccess {Number} reviewsCount The count of reviews for the counselor.
6773     * @apiSuccess {String} userId The ID of the user.
6774     * @apiSuccess {Object} counselingTable The counseling table information.
6775     * @apiSuccess {Boolean} unsupportedBrowser Indicates whether the user's browser is unsupported.
6776     * @apiSuccess {String} user_lang The native language of the user.
6777     * @apiSuccess {Object} userTimezoneData The user's timezone data.
6778     * @apiSuccess {String} userTimezoneData.city_eng The city in English.
6779     * @apiSuccess {String} userTimezoneData.utc_offset The UTC offset.
6780     * @apiSuccess {Number} userTimezoneData.country_code_id The country code ID.
6781     * @apiSuccess {String} countryTimezone The country name based on the user's timezone.
6782     * @apiSuccess {Object} counselorLampStatus The counselor lamp status.
6783     * @apiSuccess {String} userCurrentTime The current time of the user.
6784     * @apiSuccess {Boolean} login Indicates whether the user is logged in.
6785     * @apiSuccess {Boolean} canReport Indicates whether the user can report the counselor.
6786     * @apiSuccess {Object} keep_memo The memo kept by the user for the counselor.
6787     * @apiSuccess {String} keep_memo.id The ID of the memo.
6788     * @apiSuccess {String} keep_memo.memo The memo text.
6789     * @apiSuccess {Number} order The order of the reviews.
6790     * @apiSuccess {String} chatHash The chat hash for the lesson.
6791     * @apiSuccess {Object[]} counselorLessonHistory The lesson history of the counselor.
6792     * @apiSuccess {Object} counselorLessonHistory.LessonOnairsLog The lesson on-air log.
6793     * @apiSuccess {String} counselorLessonHistory.LessonOnairsLog.start_time The start time of the lesson.
6794     * @apiSuccess {String} formattedLatestLessonDate The formatted date of the latest lesson.
6795     * @apiSuccess {Number} lessonHistoryCount The count of lessons in the lesson history.
6796     * @apiSuccess {Object} latestUserLesson The latest lesson taken by the user with the counselor.
6797     * @apiSuccess {Object} latestUserLesson.LessonOnairsLog The lesson on-air log.
6798     * @apiSuccess {String} latestUserLesson.LessonOnairsLog.start_time The start time of the lesson.
6799     * @apiSuccess {Object} user The user information.
6800     * @apiSuccess {String} user.id The ID of the user.
6801     * @apiSuccess {String} user.name The name of the user.
6802     * @apiSuccess {String} user.email The email of the user.
6803     *
6804     * @apiSuccessExample {json} Success-Response:
6805     *     HTTP/1.1 200 OK
6806     *     {
6807     *         "teacher": {
6808     *             "id": "123",
6809     *             "name": "Counselor Name",
6810     *             "image_url": "http://example.com/image.jpg"
6811     *         },
6812     *         "isFav": true,
6813     *         "teacherFavsColors": {...},
6814     *         "favoriteCount": 10,
6815     *         "isHide": false,
6816     *         "isLoggedIn": true,
6817     *         "disabledSchedule": {
6818     *             "disableAll": false,
6819     *             "disabledDays": [
6820     *                 "2023-12-01",
6821     *                 "2023-12-02"
6822     *             ]
6823     *         },
6824     *         "reviewsCount": 5,
6825     *         "userId": "123",
6826     *         "counselingTable": {...},
6827     *         "unsupportedBrowser": false,
6828     *         "user_lang": "en",
6829     *         "userTimezoneData": {
6830     *             "city_eng": "Tokyo",
6831     *             "utc_offset": "+09:00",
6832     *             "country_code_id": 81
6833     *         },
6834     *         "countryTimezone": "Japan",
6835     *         "counselorLampStatus": {...},
6836     *         "userCurrentTime": "2023/12/01 10:00",
6837     *         "login": true,
6838     *         "canReport": true,
6839     *         "keep_memo": {
6840     *             "id": "1",
6841     *             "memo": "This is a memo."
6842     *         },
6843     *         "order": 0,
6844     *         "chatHash": "example_chat_hash",
6845     *         "counselorLessonHistory": [
6846     *             {
6847     *                 "LessonOnairsLog": {
6848     *                     "start_time": "2023-12-01 10:00:00"
6849     *                 }
6850     *             }
6851     *         ],
6852     *         "formattedLatestLessonDate": "2023-12-01 (Fri)",
6853     *         "lessonHistoryCount": 5,
6854     *         "latestUserLesson": {
6855     *             "LessonOnairsLog": {
6856     *                 "start_time": "2023-12-01 10:00:00"
6857     *             }
6858     *         },
6859     *         "user": {
6860     *             "id": "123",
6861     *             "name": "John Doe",
6862     *             "email": "john.doe@test.com"
6863     *         }
6864     *     }
6865     *
6866     * @apiError {String} status The status of the request (NG).
6867     * @apiError {String} message The error message.
6868     *
6869     * @apiErrorExample {json} Error-Response:
6870     *     HTTP/1.1 400 Bad Request
6871     *     {
6872     *         "status": "NG",
6873     *         "message": "Invalid request."
6874     *     }
6875     * 
6876     * @apiSampleRequest off
6877     */
6878    public function counselor() {
6879        // NC-9875 start
6880        if ($this->localizeDir == 'ko' || $this->localizeDir == 'zh-tw' || $this->localizeDir == 'vi' || $this->localizeDir =='pt-br') {
6881            return $this->redirect(myTools::getUrl());
6882        }
6883
6884        $where = array(
6885            'user_id' => $this->Auth->user('id'),
6886            'teacher_id' => Configure::read('default_counselor_detail')
6887        );
6888
6889        if ((BlockListTable::isUserBlocked($where) == true) || ($this->BlockList->isTeacherHide($where) == true)) {
6890            return $this->redirect('/mypage');
6891        }
6892
6893        // NC-6615 check if user can report the teacher
6894        $canReport = true;
6895        if (isset($this->sharedUserData['User'])) {
6896            $userData = new UserTable($this->sharedUserData['User']);
6897            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
6898            $userMemberTypeCanDoCounselingArr = Configure::read('counselor_allowed_membership_index_data');
6899            $canReport = $userData->getMembershipTypeIndex();
6900            $membershipIndex = $canReport;
6901            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
6902
6903            //NJ-9489 - redirect to top page if payment type is not allowed
6904            $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
6905
6906            // NJ-1454 - redirect to top page if membership type is not allowed
6907            if( !in_array($membershipIndex,$userMemberTypeCanDoCounselingArr) ) {
6908                return $this->redirect(myTools::getUrl());
6909            }
6910            CakeLog::write('debug', '_userPaymentPlan: ' . $_userPaymentPlan);
6911            CakeLog::write('debug', 'counselor.not_allowed_payment_plan_id: ' . json_encode(Configure::read('counselor.not_allowed_payment_plan_id')));
6912            // NJ-9489 - redirect to top page if payment plan is not allowed
6913            if( 
6914                !$_userPaymentPlan ||
6915                in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
6916             ) {
6917                return $this->redirect(myTools::getUrl());
6918            }
6919        }
6920
6921        // NC-9875 end
6922        $counselor = $this->Teacher->getDefaultCounselorData();
6923        $this->set('teacher', $counselor);
6924
6925        //NJ-20069 counselor
6926        if(!$this->RequestHandler->isMobile()) {
6927            $lessonHistory = $this->LessonSchedule->latestCounselorLessonHistory($this->Auth->user('id'), null);
6928            $latestUserLesson = isset($lessonHistory['lessonHistory'][0]) ? $lessonHistory['lessonHistory'][0] : null;
6929            $lessonHistoryCount = isset($lessonHistory['lessonHistory']) ? count($lessonHistory['lessonHistory']) : 0;
6930            
6931            $formattedLatestLessonData = "";
6932            if(!empty($latestUserLesson))
6933            $formattedLatestLessonDate = date('Y-m-d',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])). " (" . date('D',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])) . ") ";
6934            
6935            $this->set('counselorLessonHistory', $lessonHistory['lessonHistory'] ?? []);
6936            $this->set('formattedLatestLessonDate', $formattedLatestLessonDate ?? "");
6937            $this->set('lessonHistoryCount', $lessonHistoryCount);
6938            $this->set('latestUserLesson', $latestUserLesson);
6939        }
6940        
6941        //test
6942
6943
6944
6945        # favorite
6946        $where = array(
6947            'UsersFavorite.user_id'     => $this->Auth->user('id'),
6948            'UsersFavorite.teacher_id'     => Configure::read('default_counselor_detail')
6949        );
6950        $isFav = $this->UsersFavorite->find('count', array('conditions' => $where));
6951        $this->set('isFav', $isFav);
6952        $favIds = $isFav ? [Configure::read('default_counselor_detail')] : [];
6953        $teacherFavColor = $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => $favIds]);
6954        $teacherFavsColors = $this->UsersFavoriteCategoriesTeacher->parseToHexColor([
6955            'favIds' => $favIds,
6956            'favIdsTeacherCategory' => $teacherFavColor
6957        ]);
6958        $this->set('teacherFavsColors', $teacherFavsColors);
6959        # count favorite users
6960        $where = array(
6961            'UsersFavorite.teacher_id'  => Configure::read('default_counselor_detail')
6962        );
6963        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => $where));
6964        $this->set('favoriteCount', $favoriteCount);
6965
6966        # is teacher hide
6967        $where = array(
6968            'user_id' => $this->Auth->user('id'),
6969            'teacher_id' => Configure::read('default_counselor_detail')
6970        );
6971        $isHide = $this->BlockList->isTeacherHide($where);
6972        $this->set('isHide', $isHide);
6973
6974        //NC-7984 start
6975        $this->set('isLoggedIn', $this->Auth->loggedIn());
6976        $this->counselorLatestLessonHistory($this->Auth->user('id'));
6977        //NC-7984 end
6978
6979        $userId = $this->Auth->user('id');
6980        $counselingTable = $this->CounselingTable;
6981        // - get disabled dates
6982        $counselorIds = $this->Teacher->getCounselorId();
6983        $disabledSchedule = $this->LessonSchedule->getDisabledDays(array(
6984            'userId' => $userId,
6985            'teacherId' => $counselorIds,
6986            'timeDiff' => $this->timeDiff
6987        ));
6988        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
6989        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
6990        $options['language_id'] = $reviewLanguage[0] ?? null;
6991        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
6992        $reviewsCount = $this->UsersClassEvaluation->getCommentCount($counselorIds, $options);
6993
6994        // - set data to view
6995        $setData = array(
6996            'reviewsCount' => $reviewsCount,
6997            'userId' => $userId,
6998            'disabledSchedule' => json_encode($disabledSchedule),
6999            'counselingTable' => $counselingTable
7000        );
7001        $unsupportedBrowser = false;
7002        $browser = $this->request->header('User-Agent');
7003
7004        if (preg_match('/(OPR|Opera)/i', $browser)) { 
7005            $unsupportedBrowser = true;
7006        } elseif (preg_match('/(Edg|Edge|Chrome|Firefox|Safari)/i', $browser)) { 
7007            $unsupportedBrowser = false;
7008        } else { 
7009            $unsupportedBrowser = true;
7010        }
7011
7012        $this->set('unsupportedBrowser', $unsupportedBrowser);
7013        $this->set($setData);
7014
7015        if (isset($this->sharedUserData['User'])) {
7016            $this->set('user_lang', $this->sharedUserData['User']['native_language2']);
7017        }
7018
7019        # get user timezone
7020        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
7021        $user_timezone_data = $this->Timezone->find('first',
7022            array(
7023                'fields' => array(
7024                    'Timezone.city_eng',
7025                    'Timezone.utc_offset',
7026                    'Timezone.country_code_id'
7027                ),
7028                'conditions' => array(
7029                    'Timezone.id' => $user_timezone_id
7030                ),
7031                'recursive' => -1
7032            )
7033        );
7034
7035        // - NJ-3653 get country
7036        $countryTimezone = null;
7037        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
7038            // - Get all country Code
7039            $countryOptions = $this->Timezone->countryOptions();
7040
7041            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
7042            $countryName = $countryOptions[$countryCodeId]['country_name'];
7043
7044            if (isset($countryName) && $countryName) {
7045                $countryTimezone = $countryName;
7046            }
7047        }
7048
7049        // NJ-20272:get counselor lamp status 
7050        $counselorLampStatus = $this->Teacher->getCounselorLampStatus();
7051
7052        $this->set('countryTimezone', $countryTimezone);
7053        $this->set('userTimezoneData', $user_timezone_data);
7054        $this->set('counselorLampStatus',$counselorLampStatus);
7055
7056        #user time
7057        $datetime = date('Y-m-d H:i:s');
7058        $localTime = $this->displayTime;
7059        // NJ-29496
7060        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
7061            $formattedDate = date('d/m/Y G:i', $localTime);
7062        } else {
7063            $formattedDate = date('Y/m/d G:i', $localTime);
7064        }
7065        $this->set('userCurrentTime', $formattedDate);    
7066        $this->set('login', $this->Auth->loggedIn());
7067        $this->set('canReport', $canReport);
7068
7069        $params = array(
7070            'this' => $this,
7071            'forceMobile' => false,
7072            'spView' => '/Mobile/Teacher/counselor_detail',
7073            'view' => '/Waiting/counselor_detail',
7074            'layout' => 'mobile',
7075            'mobile' => null,
7076            'pc' => null
7077        );
7078
7079        //NC-7603 get keep memo
7080        $this->UsersMemo->openDBReplica();
7081        $getKeepMemo = $this->UsersMemo->find('first', array(
7082            'fields' => array(
7083                'id',
7084                'memo'
7085            ),
7086            'conditions' => array(
7087                'user_id' => $this->Auth->user('id'),
7088                'is_counselor' => true
7089            ),
7090            'order' => array('id DESC'),
7091        ));
7092        $this->UsersMemo->closeDBReplica();
7093
7094        // - set keep memo
7095        $this->set('keep_memo', $getKeepMemo);
7096
7097        //set meta for teacher or counselor image 
7098        $counselorObject = new TeacherTable($counselor['Teacher']);
7099        $_teacherImgUrl = $counselorObject->getImageUrl();
7100
7101        //if has image 
7102        if ($_teacherImgUrl) {
7103
7104            //check if teacher has no image 
7105            if (empty($counselorObject->image_url) || !$counselorObject->image_url) {
7106                $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
7107                $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
7108            }
7109
7110            $this->set('meta_teacher_img',$_teacherImgUrl);        
7111        }
7112
7113        
7114        // - set review order
7115        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
7116
7117        // class evaluation
7118        if ($this->request->query('chatHash')) {
7119            $chatHash = $this->request->query('chatHash');
7120
7121            // Check if chatHash is valid
7122            $this->LessonOnairsLog->openDBReplica();
7123            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
7124            $this->LessonOnairsLog->closeDBReplica();
7125
7126            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
7127                $this->LessonOnair->openDBReplica();
7128                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
7129                $this->LessonOnair->closeDBReplica();
7130
7131                if(!$allData) {
7132                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
7133                }
7134            }
7135
7136            if(!empty($this->sharedUserData['User'])){
7137                // - campaing stamps
7138                $this->getActiveCampaignStampData();
7139            }
7140
7141            $this->set('chatHash', $chatHash);
7142        }
7143        $this->set('counselor_teacher_detail', 1);
7144
7145        // - get user information
7146        $this->User->openDBReplica();
7147        $this->User->recursive = -1;
7148        $data = $this->User->findById($userId);
7149        $this->User->closeDBReplica();
7150
7151        $user = isset($data['User'])?$data['User']: null;
7152        $this->set('counselorObject', $counselorObject);
7153        $this->set('user', $user);
7154        myTools::render($params);
7155    }
7156
7157    /**
7158     * @api {get} /user/customersupport_detail customersupport()
7159     * @apiName customersupport
7160     * @apiGroup Waiting
7161     * @apiDescription Retrieves the customer support details for the authenticated user in Native Camp. It returns various information about the user's customer support status, lesson history, and more.
7162     * 
7163     * @apiSuccess {Boolean} isHide Indicates whether the teacher is hidden by the user.
7164     * @apiSuccess {Boolean} isLoggedIn Indicates whether the user is logged in.
7165     * @apiSuccess {Number} reviewsCount The count of reviews for the counselor.
7166     * @apiSuccess {String} userId The ID of the user.
7167     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
7168     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
7169     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
7170     * @apiSuccess {Object} counselingTable The counseling table information.
7171     * @apiSuccess {Boolean} unsupportedBrowser Indicates whether the user's browser is unsupported.
7172     * @apiSuccess {String} user_lang The native language of the user.
7173     * @apiSuccess {Object} userTimezoneData The user's timezone data.
7174     * @apiSuccess {String} userTimezoneData.city_eng The city in English.
7175     * @apiSuccess {String} userTimezoneData.utc_offset The UTC offset.
7176     * @apiSuccess {Number} userTimezoneData.country_code_id The country code ID.
7177     * @apiSuccess {String} countryTimezone The country name based on the user's timezone.
7178     * @apiSuccess {Object} counselorLampStatus The counselor lamp status.
7179     * @apiSuccess {String} userCurrentTime The current time of the user.
7180     * @apiSuccess {Boolean} login Indicates whether the user is logged in.
7181     * @apiSuccess {Boolean} canReport Indicates whether the user can report the teacher.
7182     * @apiSuccess {Object} keep_memo The memo kept by the user for the teacher.
7183     * @apiSuccess {String} keep_memo.id The ID of the memo.
7184     * @apiSuccess {String} keep_memo.memo The memo text.
7185     * @apiSuccess {Number} order The order of the reviews.
7186     * @apiSuccess {String} chatHash The chat hash for the lesson.
7187     * @apiSuccess {Object[]} counselorLessonHistory The lesson history of the counselor.
7188     * @apiSuccess {Object} counselorLessonHistory.LessonOnairsLog The lesson on-air log.
7189     * @apiSuccess {String} counselorLessonHistory.LessonOnairsLog.start_time The start time of the lesson.
7190     * @apiSuccess {String} formattedLatestLessonDate The formatted date of the latest lesson.
7191     * @apiSuccess {Number} lessonHistoryCount The count of lessons in the lesson history.
7192     * @apiSuccess {Object} latestUserLesson The latest lesson taken by the user with the counselor.
7193     * @apiSuccess {Object} latestUserLesson.LessonOnairsLog The lesson on-air log.
7194     * @apiSuccess {String} latestUserLesson.LessonOnairsLog.start_time The start time of the lesson.
7195     * @apiSuccess {Object} user The user information.
7196     * @apiSuccess {String} user.id The ID of the user.
7197     * @apiSuccess {String} user.name The name of the user.
7198     * @apiSuccess {String} user.email The email of the user.
7199     *
7200     * @apiSuccessExample {json} Success-Response:
7201     *     {
7202     *         "isHide": false,
7203     *         "isLoggedIn": true,
7204     *         "reviewsCount": 10,
7205     *         "userId": "123",
7206     *         "disabledSchedule": {
7207     *             "disableAll": false,
7208     *             "disabledDays": [
7209     *                 "2023-12-01",
7210     *                 "2023-12-02"
7211     *             ]
7212     *         },
7213     *         "counselingTable": {...},
7214     *         "unsupportedBrowser": false,
7215     *         "user_lang": "en",
7216     *         "userTimezoneData": {
7217     *             "city_eng": "Tokyo",
7218     *             "utc_offset": "+09:00",
7219     *             "country_code_id": 81
7220     *         },
7221     *         "countryTimezone": "Japan",
7222     *         "counselorLampStatus": {...},
7223     *         "userCurrentTime": "2023/12/01 10:00",
7224     *         "login": true,
7225     *         "canReport": true,
7226     *         "keep_memo": {
7227     *             "id": "1",
7228     *             "memo": "This is a memo."
7229     *         },
7230     *         "order": 0,
7231     *         "chatHash": "example_chat_hash",
7232     *         "counselorLessonHistory": [
7233     *             {
7234     *                 "LessonOnairsLog": {
7235     *                     "start_time": "2023-12-01 10:00:00"
7236     *                 }
7237     *             }
7238     *         ],
7239     *         "formattedLatestLessonDate": "2023-12-01 (Fri)",
7240     *         "lessonHistoryCount": 5,
7241     *         "latestUserLesson": {
7242     *             "LessonOnairsLog": {
7243     *                 "start_time": "2023-12-01 10:00:00"
7244     *             }
7245     *         },
7246     *         "user": {
7247     *             "id": "123",
7248     *             "name": "John Doe",
7249     *             "email": "john.doe@test.com"
7250     *         }
7251     *     }
7252     *
7253     * @apiError {String} status The status of the request (NG).
7254     * @apiError {String} message The error message.
7255     *
7256     * @apiErrorExample {json} Error-Response:
7257     *     {
7258     *         "status": "NG",
7259     *         "message": "Invalid request."
7260     *     }
7261     * 
7262     * @apiSampleRequest off
7263     */
7264    public function customersupport() {
7265
7266        // NC-9875 start
7267        if ($this->localizeDir == 'ko' || $this->localizeDir == 'zh-tw' || $this->localizeDir == 'vi') {
7268            return $this->redirect(myTools::getUrl());
7269        }
7270
7271        $isCustomerSupportUser = $this->UsersDetail->isCustomerSupportUser($this->Auth->user('id'));
7272        if(!$isCustomerSupportUser){
7273            return $this->redirect('/mypage');
7274        }
7275
7276        // NJ-54011: Check if user is Free trial not conducted yet.
7277        if ($this->userMembershipType == 13) {
7278            $this->set('membershipType', $this->userMembershipType);
7279        }
7280
7281        $where = array(
7282            'user_id' => $this->Auth->user('id'),
7283            'teacher_id' => Configure::read('default_counselor_detail')
7284        );
7285
7286        if ((BlockListTable::isUserBlocked($where) == true) || ($this->BlockList->isTeacherHide($where) == true)) {
7287            return $this->redirect('/mypage');
7288        }
7289
7290        // NC-6615 check if user can report the teacher
7291        $canReport = true;
7292        if (isset($this->sharedUserData['User'])) {
7293            $userData = new UserTable($this->sharedUserData['User']);
7294            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
7295            $userMemberTypeCanDoCounselingArr = Configure::read('counselor_allowed_membership_index_data');
7296            $canReport = $userData->getMembershipTypeIndex();
7297            $membershipIndex = $canReport;
7298            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
7299            //NJ-9489 - redirect to top page if payment type is not allowed
7300            $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
7301        }
7302
7303        # is teacher hide
7304        $where = array(
7305            'user_id' => $this->Auth->user('id'),
7306            'teacher_id' => Configure::read('default_customer_support_detail')
7307        );
7308        $isHide = $this->BlockList->isTeacherHide($where);
7309        $this->set('isHide', $isHide);
7310
7311        $counselor = $this->Teacher->getDefaultCustomerSupportDetail();
7312
7313        //NC-7984 start
7314        $this->set('isLoggedIn', $this->Auth->loggedIn());
7315        $this->counselorLatestLessonHistory($this->Auth->user('id'));
7316        //NC-7984 end
7317
7318        $userId = $this->Auth->user('id');
7319        $counselingTable = $this->CounselingTable;
7320        // - get disabled dates
7321        $counselorIds = $this->Teacher->getCounselorId();
7322        $disabledSchedule = $this->LessonSchedule->getDisabledDays(array(
7323            'userId' => $userId,
7324            'teacherId' => $counselorIds,
7325            'timeDiff' => $this->timeDiff
7326        ));
7327        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
7328        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
7329        $options['language_id'] = $reviewLanguage[0];
7330        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
7331        $reviewsCount = $this->UsersClassEvaluation->getCommentCount($counselorIds, $options);
7332
7333        // - set data to view
7334        $setData = array(
7335            'reviewsCount' => $reviewsCount,
7336            'userId' => $userId,
7337            'disabledSchedule' => json_encode($disabledSchedule),
7338            'counselingTable' => $counselingTable
7339        );
7340        $unsupportedBrowser = false;
7341        $browser =  $this->request->header('User-Agent');
7342
7343        if (preg_match('/(OPR|Opera)/i', $browser)) { 
7344            $unsupportedBrowser = true;
7345        } elseif (preg_match('/(Edg|Edge|Chrome|Firefox|Safari)/i', $browser)) { 
7346            $unsupportedBrowser = false;
7347        } else { 
7348            $unsupportedBrowser = true;
7349        }
7350        $this->set('unsupportedBrowser', $unsupportedBrowser);
7351        $this->set($setData);
7352
7353        if (isset($this->sharedUserData['User'])) {
7354            $this->set('user_lang', $this->sharedUserData['User']['native_language2']);
7355        }
7356
7357        # get user timezone
7358        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
7359        $user_timezone_data = $this->Timezone->find('first',
7360            array(
7361                'fields' => array(
7362                    'Timezone.city_eng',
7363                    'Timezone.utc_offset',
7364                    'Timezone.country_code_id'
7365                ),
7366                'conditions' => array(
7367                    'Timezone.id' => $user_timezone_id
7368                ),
7369                'recursive' => -1
7370            )
7371        );
7372
7373        // - NJ-3653 get country
7374        $countryTimezone = null;
7375        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
7376            // - Get all country Code
7377            $countryOptions = $this->Timezone->countryOptions();
7378
7379            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
7380            $countryName = $countryOptions[$countryCodeId]['country_name'];
7381
7382            if (isset($countryName) && $countryName) {
7383                $countryTimezone = $countryName;
7384            }
7385        }
7386
7387        // NJ-20272:get counselor lamp status 
7388        $counselorLampStatus = $this->Teacher->getCounselorLampStatus();
7389
7390        $this->set('countryTimezone', $countryTimezone);
7391        $this->set('userTimezoneData', $user_timezone_data);
7392        $this->set('counselorLampStatus',$counselorLampStatus);
7393
7394        #user time
7395        $datetime = date('Y-m-d H:i:s');
7396        $localTime = $this->displayTime;
7397        // NJ-29496
7398        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
7399            $formattedDate = date('d/m/Y G:i', $localTime);
7400        } else {
7401            $formattedDate = date('Y/m/d G:i', $localTime);
7402        }
7403        $this->set('userCurrentTime', $formattedDate);    
7404        $this->set('login', $this->Auth->loggedIn());
7405        $this->set('canReport', $canReport);
7406
7407        $params = array(
7408            'this' => $this,
7409            'forceMobile' => false,
7410            'spView' => '/Mobile/Teacher/counselor_detail',
7411            'view' => '/Waiting/customersupport_detail',
7412            'layout' => 'mobile',
7413            'mobile' => null,
7414            'pc' => null
7415        );
7416
7417        //NC-7603 get keep memo
7418        $this->UsersMemo->openDBReplica();
7419        $getKeepMemo = $this->UsersMemo->find('first', array(
7420            'fields' => array(
7421                'id',
7422                'memo'
7423            ),
7424            'conditions' => array(
7425                'user_id' => $this->Auth->user('id'),
7426                'teacher_id' => Configure::read('default_customer_support_detail')
7427            ),
7428            'order' => array('id DESC'),
7429        ));
7430        $this->UsersMemo->closeDBReplica();
7431
7432        // - set keep memo
7433        $this->set('keep_memo', $getKeepMemo);
7434
7435        // - set review order
7436        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
7437
7438        // class evaluation
7439        if ($this->request->query('chatHash')) {
7440            $chatHash = $this->request->query('chatHash');
7441
7442            // Check if chatHash is valid
7443            $this->LessonOnairsLog->openDBReplica();
7444            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
7445            $this->LessonOnairsLog->closeDBReplica();
7446
7447            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
7448                $this->LessonOnair->openDBReplica();
7449                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
7450                $this->LessonOnair->closeDBReplica();
7451
7452                if(!$allData) {
7453                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
7454                }
7455            }
7456
7457            if(!empty($this->sharedUserData['User'])){
7458                // - campaing stamps
7459                $this->getActiveCampaignStampData();
7460            }
7461
7462            $this->set('chatHash', $chatHash);
7463        }
7464
7465        $lessonHistory = $this->LessonSchedule->latestCounselorLessonHistory($this->Auth->user('id'), null, true);
7466        $latestUserLesson = ($lessonHistory['lessonHistory'][0]);
7467        $lessonHistoryCount = count($lessonHistory['lessonHistory']);
7468        $lessonHistoryCount = 0;
7469        
7470        $formattedLatestLessonData = "";
7471        if(!empty($latestUserLesson))
7472        $formattedLatestLessonDate = date('Y-m-d',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])). " (" . date('D',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])) . ") ";
7473        
7474        $this->set('counselorLessonHistory', $lessonHistory['lessonHistory']);
7475        $this->set('formattedLatestLessonDate', $formattedLatestLessonDate);
7476        $this->set('lessonHistoryCount', $lessonHistoryCount);
7477        $this->set('latestUserLesson', $latestUserLesson);
7478
7479        // - get user information
7480        $this->User->openDBReplica();
7481        $this->User->recursive = -1;
7482        $data = $this->User->findById($userId);
7483        $this->User->closeDBReplica();
7484
7485        $user = isset($data['User'])?$data['User']: null;
7486        $this->set('teacher', $counselor);
7487        $this->set('user', $user);
7488        $this->set('isCustomerSupportUser', true);
7489         myTools::render($params);
7490        
7491    }
7492
7493    //end of customer support func
7494
7495
7496
7497    /**
7498     * @api {post} /user/waiting/counselingGetDisabledDates counselingGetDisabledDates()
7499     * @apiName counselingGetDisabledDates
7500     * @apiGroup Waiting
7501     * @apiDescription Retrieves the disabled dates for counseling sessions for the authenticated user in Native Camp. It returns the dates when counseling sessions are not available.
7502     *
7503     * @apiBody {String} userId The ID of the user.
7504     * 
7505     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
7506     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
7507     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
7508     *
7509     * @apiSuccessExample {json} Success-Response:
7510     *     {
7511     *         "disableAll": false,
7512     *         "disabledDays": [
7513     *             "2023-12-01",
7514     *             "2023-12-02"
7515     *         ]
7516     *     }
7517     *
7518     * @apiError {String} status The status of the request (NG).
7519     * @apiError {String} message The error message.
7520     *
7521     * @apiErrorExample {json} Error-Response:
7522     *     {
7523     *         "status": "NG",
7524     *         "message": "Invalid request."
7525     *     }
7526     * 
7527     * @apiSampleRequest off
7528     */
7529    public function counselingGetDisabledDates() {
7530        $this->autoRender = false;
7531        if ($this->request->is('ajax')) {
7532            $data = $this->request->data;
7533            // - get disabled dates
7534            $counselorIds = $this->Teacher->getCounselorId();
7535            $disabledSchedule = $this->LessonSchedule->getDisabledDays(array(
7536                'userId' => $data['userId'],
7537                'teacherId' => $counselorIds,
7538                'timeDiff' => $this->timeDiff
7539            ));
7540            return json_encode($disabledSchedule);
7541        }
7542    }
7543
7544    /**
7545     * @api {post} /user/waiting/counselorSlots counselorSlots()
7546     * @apiName counselorSlots
7547     * @apiGroup Waiting
7548     * @apiDescription Retrieves the available slots for counseling sessions for the authenticated user in Native Camp. It returns the available slots and their states.
7549     *
7550     * @apiBody {String} userId The ID of the user.
7551     * @apiBody {Boolean} [ifForCancellation=false] Indicates whether the request is for cancellation.
7552     * 
7553     * @apiSuccess {Object} schedules The schedules of available slots.
7554     * @apiSuccess {String} schedules.day The day of the week.
7555     * @apiSuccess {String} schedules.d The day of the month.
7556     * @apiSuccess {String} schedules.m The month.
7557     * @apiSuccess {String} schedules.y The year.
7558     * @apiSuccess {Object} schedules.slots The slots for the day.
7559     * @apiSuccess {Number} schedules.slots.open_counselor The number of open counselors.
7560     * @apiSuccess {Number} schedules.slots.state The state of the slot (1: Reserved by user, 2: Reserved by others, 3: Not available, 4: Fully booked, 5: Can't reserve due to limit, 6: Not available within 10 minutes, 7: Available).
7561     * @apiSuccess {Number} schedules.slots.hour The hour of the slot.
7562     * @apiSuccess {Number} schedules.slots.minute The minute of the slot.
7563     * @apiSuccess {Boolean} schedules.slots.is_reserve Indicates whether the slot is reserved by the user.
7564     * @apiSuccess {Number} [schedules.slots.limited_plan_reservation] Indicates whether the slot is limited plan reservation (if applicable).
7565     *
7566     * @apiSuccessExample {json} Success-Response:
7567     *     {
7568     *         "schedules": {
7569     *             "12/01": {
7570     *                 "day": "(月)",
7571     *                 "d": "01",
7572     *                 "m": "12",
7573     *                 "y": "2023",
7574     *                 "slots": {
7575     *                     "10:00": {
7576     *                         "open_counselor": 2,
7577     *                         "state": 7,
7578     *                         "hour": 10,
7579     *                         "minute": 0,
7580     *                         "is_reserve": false
7581     *                     },
7582     *                     "10:30": {
7583     *                         "open_counselor": 1,
7584     *                         "state": 1,
7585     *                         "hour": 10,
7586     *                         "minute": 30,
7587     *                         "is_reserve": true
7588     *                     }
7589     *                 }
7590     *             }
7591     *         }
7592     *     }
7593     *
7594     * @apiError {String} status The status of the request (NG).
7595     * @apiError {String} message The error message.
7596     *
7597     * @apiErrorExample {json} Error-Response:
7598     *     {
7599     *         "status": "NG",
7600     *         "message": "Invalid request."
7601     *     }
7602     * 
7603     * @apiSampleRequest off
7604     */
7605    public function counselorSlots() {
7606        // $this->autoRender = false;
7607        $data = $this->request->data;
7608        $ifForCancellation = (isset($data['ifForCancellation']) && $data['ifForCancellation']) ? true : false;
7609        $user_id = isset($data['userId']) ? $data['userId'] : '';
7610        $this->set('userId', $user_id);
7611        $nowTime = time();
7612        $userTime = $this->displayTime;
7613        $start_date = date('Y-m-d H:i', $nowTime);
7614        $corporateLightUser = false;
7615        $corporateLimitedUser = false;
7616        $slots = array(
7617            'show_caution_flg' => 0,
7618            'start_date' => $start_date,
7619            'states' => NULL
7620        );
7621        // check corporate user
7622        $getCorporateType = $this->User->find("first",array(
7623                "conditions" => array( "User.id" => $user_id ),
7624                "fields" => array("User.payment_plan_id"),
7625                "recursive" => -1,
7626            )
7627        );
7628        
7629        if ($getCorporateType && isset($getCorporateType["User"]["payment_plan_id"]) ) {
7630            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($getCorporateType["User"]["payment_plan_id"]);
7631            
7632            $corporateLimitedUser = ($corporateType == Configure::read("corporate_type.limited"));
7633            $corporateLightUser = ($corporateType == Configure::read("corporate_type.light"));
7634        }
7635        $this->set('corporateLimitedUser', $corporateLimitedUser);
7636        $this->set('corporateLightUser', $corporateLightUser);
7637        // - if reservation exceeds cancellation already
7638        $sharedUserDataCorporateType = myTools::getCoporateTypeUsingPaymentPlanId($this->sharedUserData['User']['payment_plan_id']);
7639        $slots['show_caution_flg'] = ($this->LessonSchedule->reservationCautionFlag(array('userId' => $user_id))) ? 1 : 0;
7640        $counselorIds = $this->Teacher->getCounselorId();
7641        $result = $this->LessonSchedule->getCounselorSlots(array(
7642            'counselor_ids' => $counselorIds,
7643            'user_id' => $user_id,
7644            'start_day' => $start_date,
7645            'include_past' => true,
7646            'corporateLimitedUser' => $corporateLimitedUser,
7647            'corporateLightUser' => (isset($sharedUserDataCorporateType) && $sharedUserDataCorporateType == Configure::read("corporate_type.light")) ? true : false
7648        ));
7649
7650        $weekday = array( __d('waiting','(日)'), __d('waiting','(月)'), __d('waiting','(火)'), __d('waiting','(水)'), __d('waiting','(木)'), __d('waiting','(金)'), __d('waiting','(土)') );
7651        $openSlots = array();
7652        $schedules = array();
7653
7654        if (!$result['error']) {
7655            // - get days
7656            for ($i=0; $i<=7; $i++) {
7657                $cTime = strtotime("+" . $i . " days", $userTime);
7658                $schedDate = date('m/d', $cTime);
7659                $schedules[$schedDate] = array(
7660                    'day' => $weekday[date("w", $cTime)],
7661                    'd' => date('d', $cTime),
7662                    'm' => date('m', $cTime),
7663                    'y' => date('Y', $cTime)
7664                );
7665            }
7666
7667            // - arrange open_slot
7668            foreach ($result['openSlotData'] as $slot) {
7669                $shiftTime = TimezoneTable::computeTimeToUser(array(
7670                    'time' => strtotime($slot['ShiftWorkOn']['lesson_time']),
7671                    'timestamp' => $this->timeDiffSecond
7672                ));
7673                $openSlots[date('Y-m-d H:i:s', $shiftTime)] = $slot[0]['shiftCount'];
7674                $formattedLessonTime = date('Y-m-d H:i', $shiftTime);
7675                $lessonHour = date('H', $shiftTime);
7676                $lessonMinute = date('i', $shiftTime);
7677                $lessonDateTime = explode(' ', $formattedLessonTime);
7678                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
7679                $lessonDate = date('m/d', strtotime($lessonDate));
7680                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
7681
7682                // - state 7 : Available
7683                $state = 7;
7684
7685                //check before 10minutes
7686                if ((strtotime($slot['ShiftWorkOn']['lesson_time']) - strtotime($start_date)) <= 600) {
7687                    $state = 6;
7688                }
7689
7690                $schedules[$lessonDate]['slots'][$lessonTime] = array(
7691                    'open_counselor' => intval($slot[0]['shiftCount']),
7692                    'state' => $state,
7693                    'hour' => $lessonHour,
7694                    'minute' => $lessonMinute
7695                );
7696
7697                if ($corporateLimitedUser && isset($slot['TeacherRankCoin'])) {
7698                    $schedules[$lessonDate]['slots'][$lessonTime]['limited_plan_reservation'] = $slot['TeacherRankCoin']['limited_plan_reservation'];
7699                }
7700            }
7701
7702            // - counselor ids
7703            $counselorsIds = !empty($counselorIds) ? array_values($counselorIds) : array();
7704            // - counselor reservations
7705            foreach ($result['reservationData'] as $reservation) {
7706                //get timestamp adjusted to user timezone
7707                $unixUserLessonTime = TimezoneTable::computeTimeToUser(array(
7708                    'time' => strtotime($reservation['LessonSchedule']['lesson_time']),
7709                    'timestamp' => $this->timeDiffSecond
7710                ));
7711                $timeIndex = date('Y-m-d H:i:s', $unixUserLessonTime);
7712                $formattedUserLessonTime = date('Y-m-d H:i', $unixUserLessonTime);
7713
7714                $lessonHour = date('H', $unixUserLessonTime);
7715                $lessonMinute = date('i', $unixUserLessonTime);
7716                $lessonDateTime = explode(' ', $formattedUserLessonTime);
7717                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
7718                $lessonDate = date('m/d', strtotime($lessonDate));
7719                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
7720
7721                // - if my reservation
7722                if ($reservation['LessonSchedule']['user_id'] == $user_id) {
7723                    if (!in_array($reservation['LessonSchedule']['teacher_id'], $counselorsIds) && !empty($openSlots[$timeIndex])) {
7724                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 2;
7725                    } elseif (!in_array($reservation['LessonSchedule']['teacher_id'], $counselorsIds) && empty($openslot[$timeIndex])) {
7726                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 3;
7727                    } else {
7728                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 1;
7729                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
7730                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
7731                    }
7732
7733                    $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] = true;
7734
7735                // - if not my reservations
7736                } elseif ((isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] != 1)) {
7737                    $openSlots[$timeIndex]--;
7738
7739                    # to prevent the schedule of the current user being overriden by other users schedules
7740                    if (isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && isset($schedules[$lessonDate]['slots'][$lessonTime]['is_reserve']) && $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] ) {
7741                        continue;
7742                    }
7743
7744                    if (
7745                        (isset($disabledSchedule['disableAll']) && $disabledSchedule['disableAll'])
7746                        || (!empty($disabledSchedule['disabledDays']) && in_array(date('Y-m-d', $unixUserLessonTime), $disabledSchedule['disabledDays']))
7747                        && (!empty($openSlots[$timeIndex]) && $schedules[$formattedLessonTime]['state'] >= 5)
7748                    ) {
7749                        $openSlots[$timeIndex]--;
7750                        // - state 5 : can't reserve because of reservation limit
7751                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
7752                            'state' => 5,
7753                            'open_counselor' => intval($openSlots[$timeIndex]),
7754                            'hour' => $lessonHour,
7755                            'minute' => $lessonMinute
7756                        );
7757
7758                    } elseif (!empty($openSlots[$timeIndex]) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] >= 4) {
7759                        // - state 7 : Available
7760                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
7761                            'state' => 7,
7762                            'open_counselor' => intval($openSlots[$timeIndex]),
7763                            'hour' => $lessonHour,
7764                            'minute' => $lessonMinute
7765                        );
7766                    } elseif (
7767                        isset($openSlots[$timeIndex])
7768                        && $openSlots[$timeIndex] <= 0
7769                        && (
7770                            isset($schedules[$formattedLessonTime]['state'])
7771                            && $schedules[$formattedLessonTime]['state'] >= 4
7772                            || empty($schedules[$formattedLessonTime]['state'])
7773                        )
7774                    ) {
7775                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 4;
7776                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
7777                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
7778                    }
7779                }
7780            }
7781
7782            if ($ifForCancellation) {
7783                $this->autoRender = false;
7784                return json_encode($schedules);
7785            }
7786            $this->set('schedules', $schedules);
7787        }
7788    }
7789
7790    /**
7791     * @api {post} /user/waiting/avatarSlots avatarSlots()
7792     * @apiName avatarSlots
7793     * @apiGroup Waiting
7794     * @apiDescription Retrieves the available slots for avatar lessons for the authenticated user in Native Camp. It returns the schedule and availability of the slots.
7795     *
7796     * @apiBody {String} teacherId The ID of the avatar teacher.
7797     * @apiBody {Boolean} [ifForCancellation] Indicates whether the request is for cancellation.
7798     * @apiBody {String} userId The ID of the user.
7799     * 
7800     * @apiSuccess {Object} schedules The schedule and availability of the slots.
7801     * @apiSuccess {String} schedules.day The day of the week.
7802     * @apiSuccess {String} schedules.d The day of the month.
7803     * @apiSuccess {String} schedules.m The month.
7804     * @apiSuccess {String} schedules.y The year.
7805     * @apiSuccess {Object} schedules.slots The slots for each day.
7806     * @apiSuccess {Number} schedules.slots.open_avatar The number of open avatar slots.
7807     * @apiSuccess {Number} schedules.slots.state The state of the slot (1: Reserved by user, 2: Reserved by another user, 3: Reserved by another user and not available, 4: No open slots, 5: Can't reserve because of reservation limit, 6: Can't reserve because it's within 5 minutes, 7: Available).
7808     * @apiSuccess {Number} schedules.slots.hour The hour of the slot.
7809     * @apiSuccess {Number} schedules.slots.minute The minute of the slot.
7810     * @apiSuccess {Object} [schedules.slots.teacherData] The data of the teacher for the slot.
7811     * @apiSuccess {Object} [schedules.slots.ownTeacherData] The data of the user's own teacher for the slot.
7812     * @apiSuccess {Boolean} schedules.slots.is_reserve Indicates whether the slot is reserved by the user.
7813     * @apiSuccess {String} schedules.slots.teacher_id The ID of the teacher for the slot.
7814     * @apiSuccess {Object} campaignPeriod The campaign period for the avatar teacher.
7815     * @apiSuccess {String[]} times The available times for the slots.
7816     *
7817     * @apiSuccessExample {json} Success-Response:
7818     *     {
7819     *         "schedules": {
7820     *             "12/01": {
7821     *                 "day": "(月)",
7822     *                 "d": "01",
7823     *                 "m": "12",
7824     *                 "y": "2023",
7825     *                 "slots": {
7826     *                     "10:00": {
7827     *                         "open_avatar": 2,
7828     *                         "state": 7,
7829     *                         "hour": 10,
7830     *                         "minute": 0
7831     *                     },
7832     *                     "10:30": {
7833     *                         "open_avatar": 1,
7834     *                         "state": 1,
7835     *                         "hour": 10,
7836     *                         "minute": 30,
7837     *                         "ownTeacherData": {
7838     *                             "id": "123",
7839     *                             "name": "John Doe",
7840     *                             "image": "https://www.nativecamp.net/img/teacher/123.jpg"
7841     *                         }
7842     *                     }
7843     *                 }
7844     *             }
7845     *         },
7846     *         "campaignPeriod": {...},
7847     *         "times": ["00:00", "00:30", "01:00", ...]
7848     *     }
7849     *
7850     * @apiError {String} status The status of the request (NG).
7851     * @apiError {Number} content The content of the response (0: No issues).
7852     *
7853     * @apiErrorExample {json} Error-Response:
7854     *     {
7855     *         "status": "NG",
7856     *         "content": 0
7857     *     }
7858     * 
7859     * @apiSampleRequest off
7860     */
7861    public function avatarSlots() {
7862        
7863        $data = $this->request->data;
7864        $teacherId = isset($data['teacherId']) ? $data['teacherId'] : '';
7865        $ifForCancellation = (isset($data['ifForCancellation']) && $data['ifForCancellation']) ? true : false;
7866        $user_id = isset($data['userId']) ? $data['userId'] : '';
7867        $this->set('userId', $user_id);
7868        $this->set('currentAvatarId', $teacherId);
7869        $nowTime = time();
7870        $userTime = $this->displayTime;
7871        $start_date = date('Y-m-d H:i', $nowTime);
7872        $corporateLightUser = false;
7873        $corporateLimitedUser = false;
7874        $slots = array(
7875            'show_caution_flg' => 0,
7876            'start_date' => $start_date,
7877            'states' => NULL
7878        );
7879        // check corporate user
7880        $getCorporateType = $this->User->find("first",array(
7881                "conditions" => array( "User.id" => $user_id ),
7882                "fields" => array("User.payment_plan_id"),
7883                "recursive" => -1,
7884            )
7885        );
7886
7887        if ($getCorporateType && isset($getCorporateType["User"]["payment_plan_id"]) ) {
7888            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($getCorporateType["User"]["payment_plan_id"]);
7889            $corporateLightUser = ($corporateType == Configure::read("corporate_type.light"));
7890            $corporateLimitedUser = ($corporateType == Configure::read("corporate_type.limited"));
7891        }
7892
7893        $this->set('corporateLightUser', $corporateLightUser);
7894        $this->set('corporateLimitedUser', $corporateLimitedUser);
7895        // - if reservation exceeds cancellation already
7896        $slots['show_caution_flg'] = ($this->LessonSchedule->reservationCautionFlag(array('userId' => $user_id))) ? 1 : 0;
7897        $getAvatarParams = array(
7898            "avatar_id" => $teacherId,
7899            "user_id" => $user_id,
7900            "stealth_flg" => $this->Cookie->read('stealth.setting'),
7901            'corporateLimitedUser' => $corporateLimitedUser
7902        );
7903        $avatarTeacherIds = $this->Teacher->getAvatarTeacherId($getAvatarParams);
7904        $result = $this->LessonSchedule->getAvatarSlots(array(
7905            'avatar_ids' => $avatarTeacherIds,
7906            'user_id' => $user_id,
7907            'start_day' => $start_date,
7908            'include_past' => true,
7909            'corporateLimitedUser' => $corporateLimitedUser
7910        ));
7911
7912        //campaign period start and end time
7913        $campaignPeriod = null;
7914        $checkAvatarPop = $this->userAvailPopularTeacher(
7915            array(
7916                'avatar_id' => $teacherId,
7917                'user_id' => $this->Auth->user('id'),
7918                "stealth_flg" => $this->Cookie->read('stealth.setting')
7919            )
7920        );
7921        if ($result && $checkAvatarPop) {
7922            $campaignPeriod = $this->PopularTeacherCampaignPeriod->fetchCampaignPeriod(array(
7923                'user_id' => $this->Auth->user('id'),
7924                'teacher_id' => $teacherId
7925            ));
7926        }
7927
7928        $weekday = array( __d('waiting','(日)'), __d('waiting','(月)'), __d('waiting','(火)'), __d('waiting','(水)'), __d('waiting','(木)'), __d('waiting','(金)'), __d('waiting','(土)') );
7929        $openSlots = array();
7930        $schedules = array();
7931        $tempSchedules = array();
7932
7933        if (!$result['error']) {
7934            // - get days
7935            for ($i=0; $i<=7; $i++) {
7936                $cTime = strtotime("+" . $i . " days", $userTime);
7937                $schedDate = date('m/d', $cTime);
7938                $schedules[$schedDate] = array(
7939                    'day' => $weekday[date("w", $cTime)],
7940                    'd' => date('d', $cTime),
7941                    'm' => date('m', $cTime),
7942                    'y' => date('Y', $cTime)
7943                );
7944            }
7945
7946            // - arrange open_slot
7947            foreach ($result['openSlotData'] as $slot) {
7948                $shiftTime = TimezoneTable::computeTimeToUser(array(
7949                    'time' => strtotime($slot['ShiftWorkOn']['lesson_time']),
7950                    'timestamp' => $this->timeDiffSecond
7951                ));
7952                $openSlots[date('Y-m-d H:i:s', $shiftTime)] = $slot[0]['shiftCount'];
7953                $openSlotsTemp[date('Y-m-d H:i:s', $shiftTime)] = $slot[0]['shiftCount'];
7954                $formattedLessonTime = date('Y-m-d H:i', $shiftTime);
7955                $lessonHour = date('H', $shiftTime);
7956                $lessonMinute = date('i', $shiftTime);
7957                $lessonDateTime = explode(' ', $formattedLessonTime);
7958                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
7959                $lessonDate = date('m/d', strtotime($lessonDate));
7960                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
7961
7962                // - state 7 : Available
7963                $state = 7;
7964
7965                //check before 5minutes
7966                if ((strtotime($slot['ShiftWorkOn']['lesson_time']) - strtotime($start_date)) <= 300) {
7967                    $state = 6;
7968                }
7969
7970                $schedules[$lessonDate]['slots'][$lessonTime] = array(
7971                    'open_avatar' => intval($slot[0]['shiftCount']),
7972                    'state' => $state,
7973                    'hour' => $lessonHour,
7974                    'minute' => $lessonMinute
7975                );
7976
7977                $tempSchedules[$lessonDate]['slots'][$lessonTime]['open_avatar'] = intval($slot[0]['shiftCount']);
7978
7979                if ($corporateLimitedUser && isset($slot['TeacherRankCoin'])) {
7980                    $schedules[$lessonDate]['slots'][$lessonTime]['limited_plan_reservation'] = $slot['TeacherRankCoin']['limited_plan_reservation'];
7981                }
7982            }
7983
7984
7985
7986            // - counselor ids
7987            $avatarTeacherIds = !empty($avatarTeacherIds) ? array_values($avatarTeacherIds) : array();
7988            // - counselor reservations
7989            $userSchedules = [];
7990            $otherUserSchedules = [];
7991            foreach ($result['reservationData'] as $reservation) {
7992                //get timestamp adjusted to user timezone
7993                $unixUserLessonTime = TimezoneTable::computeTimeToUser(array(
7994                    'time' => strtotime($reservation['LessonSchedule']['lesson_time']),
7995                    'timestamp' => $this->timeDiffSecond
7996                ));
7997                $timeIndex = date('Y-m-d H:i:s', $unixUserLessonTime);
7998                $formattedUserLessonTime = date('Y-m-d H:i', $unixUserLessonTime);
7999
8000                $lessonHour = date('H', $unixUserLessonTime);
8001                $lessonMinute = date('i', $unixUserLessonTime);
8002                $lessonDateTime = explode(' ', $formattedUserLessonTime);
8003                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
8004                $lessonDate = date('m/d', strtotime($lessonDate));
8005                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
8006                $lsDateTime = date('Y-m-d H:i', strtotime($reservation['LessonSchedule']['lesson_time']));
8007
8008                $tempSchedules[$lessonDate]['slots'][$lessonTime]['open_avatar'] = $openSlotsTemp[$timeIndex]--;
8009
8010                // - if another user reservation
8011                if ($reservation['LessonSchedule']['user_id'] != $user_id) {
8012                    $otherUserSchedules[$lessonDate][$lessonTime] = true;
8013                }
8014
8015                // - if my reservation
8016                if ($reservation['LessonSchedule']['user_id'] == $user_id) {
8017                    $userSchedules[$lessonDate][] = $lessonTime;
8018                    if (!in_array($reservation['LessonSchedule']['teacher_id'], $avatarTeacherIds) && !empty($openSlots[$timeIndex])) {
8019                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 2;
8020                        //get teacher details for other reservation
8021                        $teacherData = $this->LessonSchedule->getReservationData($lsDateTime, $user_id, $this->localizeDir);
8022                        $teacherData['icon_color'] = $this->LessonSchedule->getIconColor($teacherData, $lsDateTime);
8023                        $schedules[$lessonDate]['slots'][$lessonTime]['teacherData'] = $teacherData;
8024                    } elseif (!in_array($reservation['LessonSchedule']['teacher_id'], $avatarTeacherIds) && empty($openslot[$timeIndex])) {
8025                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 3;
8026                    } else {
8027                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 1;
8028                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
8029                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
8030
8031                        $teacherData = $this->LessonSchedule->getReservationData($lsDateTime, $user_id, $this->localizeDir);
8032                        $teacherData['icon_color'] = $this->LessonSchedule->getIconColor($teacherData, $lsDateTime);
8033                        $schedules[$lessonDate]['slots'][$lessonTime]['ownTeacherData'] = $teacherData;
8034                    }
8035
8036                    $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] = true;
8037                    $schedules[$lessonDate]['slots'][$lessonTime]['teacher_id'] = $reservation['LessonSchedule']['teacher_id'];
8038
8039                // - if not my reservations
8040                } elseif ((isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] != 1)) {
8041                    $openSlots[$timeIndex]--;
8042
8043                    if( isset($reservation['ShiftWorkOn']['hide_flg']) && $reservation['ShiftWorkOn']['hide_flg'] ) {
8044                        $openSlots[$timeIndex]++;
8045                    }
8046                    
8047                    # to prevent the schedule of the current user being overriden by other users schedules
8048                    if (isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && isset($schedules[$lessonDate]['slots'][$lessonTime]['is_reserve']) && $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] ) {
8049                        continue;
8050                    }
8051
8052                    if (
8053                        (isset($disabledSchedule['disableAll']) && $disabledSchedule['disableAll'])
8054                        || (!empty($disabledSchedule['disabledDays']) && in_array(date('Y-m-d', $unixUserLessonTime), $disabledSchedule['disabledDays']))
8055                        && (!empty($openSlots[$timeIndex]) && $schedules[$formattedLessonTime]['state'] >= 5)
8056                    ) {
8057                        $openSlots[$timeIndex]--;
8058                        // - state 5 : can't reserve because of reservation limit
8059                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
8060                            'state' => 5,
8061                            'hour' => $lessonHour,
8062                            'minute' => $lessonMinute,
8063                            'open_avatar' => intval($openSlots[$timeIndex])
8064                        );
8065
8066                    } elseif (!empty($openSlots[$timeIndex]) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] >= 4) {
8067                        // - state 7 : Available
8068                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
8069                            'state' => 7,
8070                            'hour' => $lessonHour,
8071                            'minute' => $lessonMinute,
8072                            'open_avatar' => intval($openSlots[$timeIndex])
8073                        );
8074                    } elseif (
8075                        isset($openSlots[$timeIndex])
8076                        && $openSlots[$timeIndex] <= 0
8077                        && (
8078                            isset($schedules[$formattedLessonTime]['state'])
8079                            && $schedules[$formattedLessonTime]['state'] >= 4
8080                            || empty($schedules[$formattedLessonTime]['state'])
8081                        )
8082                    ) {
8083                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 4;
8084                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
8085                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
8086                        $schedules[$lessonDate]['slots'][$lessonTime]['open_avatar'] = intval($openSlots[$timeIndex]);
8087                    }
8088                }
8089            }
8090
8091            // User priority, override display schedules state
8092            foreach ($userSchedules as $lesson_date => $slots) {
8093                foreach ($slots as $lesson_time) {
8094                    // Override state when slot reserved by other
8095                    if(!empty($state = $schedules[$lesson_date]['slots'][$lesson_time]['state']) && $state === 2
8096                        && !empty($otherUserSchedules[$lesson_date][$lesson_time])) {
8097                        $schedules[$lesson_date]['slots'][$lesson_time]['state'] = 3;
8098                    }
8099                    $schedules[$lesson_date]['slots'][$lesson_time]['open_avatar'] = $tempSchedules[$lesson_date]['slots'][$lesson_time]['open_avatar'];
8100                }
8101
8102            }
8103
8104            $resData = $this->LessonSchedule->getHiddenReservation([
8105                'user_id' => $user_id
8106            ]);
8107
8108            if ($resData) {
8109                foreach ($resData as $key => $row) {
8110                    //get timestamp adjusted to user timezone
8111                    $unixUserLessonTime = TimezoneTable::computeTimeToUser(array(
8112                        'time' => strtotime($key),
8113                        'timestamp' => $this->timeDiffSecond
8114                    ));
8115                    $timeIndex = date('Y-m-d H:i:s', $unixUserLessonTime);
8116                    $lessonDate = date('m/d', $unixUserLessonTime);
8117                    $lessonTime = date('H:i', $unixUserLessonTime);
8118
8119                    if (
8120                        !empty($openSlots[$timeIndex]) && 
8121                        !isset($schedules[$lessonDate]['slots'][$lessonTime]['teacherData']) &&
8122                        !isset($schedules[$lessonDate]['slots'][$lessonTime]['ownTeacherData'])
8123                    ) {
8124
8125                        $lessonRequestSlotData = $this->LessonSchedule->getReservationData($key, $user_id, $this->localizeDir);
8126                        if (!empty($lessonRequestSlotData)) {
8127                            $lessonRequestSlotData['icon_color']  = $this->LessonSchedule->getIconColor($lessonRequestSlotData, $key);
8128
8129                            if (in_array($lessonRequestSlotData['teacher_id'], $avatarTeacherIds) && $lessonRequestSlotData['reservation_status'] == Configure::read('lesson_schedule.status.on_reserve')) {
8130                                $schedules[$lessonDate]['slots'][$lessonTime]['ownTeacherData'] = $lessonRequestSlotData;
8131                                $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 1;
8132                            } else {
8133                                $schedules[$lessonDate]['slots'][$lessonTime]['teacherData'] = $lessonRequestSlotData;
8134                                $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 2;
8135                            }
8136                        }
8137                    }
8138                }
8139            } 
8140
8141            if ($ifForCancellation) {
8142                $this->autoRender = false;
8143                return json_encode($schedules);
8144            }
8145            
8146            // NJ-33414
8147            $this->UsersDetail->openDBReplica();
8148            $fetchUsersDetail = $this->UsersDetail->find('first', array(
8149                'fields' => array(
8150                    'lesson_request_flg'
8151                ),
8152                'conditions' =>  array('user_id' => $this->sharedUserData['User']['id']),
8153                'recursive' => -1
8154            ));
8155            $this->UsersDetail->closeDBReplica();
8156            
8157            $times = array();
8158            $utcMin = explode(':', $this->utcOffset);
8159            if ($utcMin[1] == "45") {
8160                for ($i=0; $i<=23; $i++) {
8161                    $times[] = sprintf("%02d",$i) . ':15';
8162                    $times[] = sprintf("%02d",$i) . ':45';
8163                }
8164            } else {
8165                for ($i=0; $i<=23; $i++) {
8166                    $times[] = sprintf("%02d",$i) . ':00';
8167                    $times[] = sprintf("%02d",$i) . ':30';
8168                }
8169            }
8170            $this->set('times', $times);
8171            $this->set('teacherId', $teacherId);
8172            $this->set('schedules', $schedules);
8173            $this->set('campaignPeriod', $campaignPeriod);
8174        }
8175    }
8176
8177    /**
8178     * @api {post} /user/waiting/counselingLimit counselingLimit()
8179     * @apiName counselingLimit
8180     * @apiGroup Waiting
8181     * @apiDescription Checks the reservation and cancellation limits for counseling sessions for the authenticated user in Native Camp. It returns the status and any relevant messages or limits.
8182     *
8183     * @apiBody {String} action The action to perform (add or cancel).
8184     * @apiBody {String} [lessonDate] The date of the lesson (required for add action).
8185     * @apiBody {String} [lessonTime] The time of the lesson (required for cancel action).
8186     * 
8187     * @apiSuccess {String} status The status of the request (OK or NG).
8188     * @apiSuccess {Number} content The content of the response (0: No issues, 1: Caution flag, 2: Exceeds total reservation limit, 3: Exceeds counselor reservations per day limit, 4: Exceeds cancellation limit, 5: Beyond available days for complimentary plan, 6: Exceeds corporate light lesson limit, 7: Cancel in time not allowed).
8189     * @apiSuccess {Object} lastDetails The last counseling details.
8190     * @apiSuccess {Number} lastDetails.id The ID of the last counseling session.
8191     * @apiSuccess {String} lastDetails.lesson_time The time of the last counseling session.
8192     * @apiSuccess {Number} lastDetails.teacher_id The ID of the teacher for the last counseling session.
8193     * @apiSuccess {Number} lastDetails.user_id The ID of the user for the last counseling session.
8194     * @apiSuccess {Number} cancelCount The count of cancellations by the user.
8195     * @apiSuccess {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8196     * @apiSuccess {String} nextChargeDate The next charge date for the user.
8197     * @apiSuccess {Boolean} isExpired Indicates whether the user's coin has expired.
8198     * 
8199     * @apiSuccessExample {json} Success-Response:
8200     *     {
8201     *         "status": "OK",
8202     *         "content": 0,
8203     *         "lastDetails": {
8204     *             "id": 123456,
8205     *             "lesson_time": "2023-12-01 12:00:00",
8206     *             "teacher_id": 123,
8207     *             "user_id": 123
8208     *         },
8209     *         "cancelCount": 1,
8210     *         "displayNotice": 0,
8211     *         "nextChargeDate": "2023年12月01日",
8212     *         "isExpired": false
8213     *     }
8214     *
8215     * @apiError {String} status The status of the request (NG).
8216     * @apiError {Number} content The content of the response (0: No issues).
8217     * @apiError {Number} cancelCount The count of cancellations by the user.
8218     * @apiError {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8219     *
8220     * @apiErrorExample {json} Error-Response:
8221     *     {
8222     *         "status": "NG",
8223     *         "content": 0,
8224     *         "cancelCount": 0,
8225     *         "displayNotice": 0
8226     *     }
8227     * 
8228     * @apiSampleRequest off
8229     */
8230    public function counselingLimit() {
8231        $this->autoRender = false;
8232        if ($this->request->is('ajax')) {
8233
8234            $userCancelledReservation = 0;
8235            $userId = $this->Auth->user('id');
8236            $action = $this->request->data['action'];
8237            $content = 0;
8238            if ($action == 'add') {
8239
8240                if (empty($this->request->data['lessonDate'])) {
8241                    return json_encode(array(
8242                        'status' => 'NG',
8243                        'content' => 0
8244                    ));
8245                }
8246
8247                // if complimentary user plan
8248                $user = $this->sharedUserData['User'];
8249                if (isset($user['payment_plan_id']) && $user['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
8250                    $this->loadModel('ComplimentaryCode');
8251                    $user['lessonTime'] = date('Y-m-d', strtotime($this->request->data['lessonDate']));
8252                    if (!$result = $this->ComplimentaryCode->validateUserComplimentaryPlan($user)) {
8253                        // set beyond available days to true
8254                        return json_encode(array('status' => 'OK', 'content' => 5));
8255                    }
8256                }
8257
8258                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
8259
8260                // NC-7361 - corporate light
8261                if (isset($corporateType) && $corporateType == Configure::read('corporate_type.light')) {
8262                    if (ClassRegistry::init('Corporate')->corpLightLessonMaxLimit(array("user_id" => $userId))) {
8263                        return json_encode(array('status' => 'OK', 'content' => 6));
8264                    }
8265                }
8266
8267                // - get total reservation
8268                $totalReservation = $this->LessonSchedule->countUserTotalReservation(array('userId' => $userId));
8269
8270                // - check if total reservation exceeds limit
8271                if ($totalReservation >= Configure::read("maximum_number_of_total_reservation")) {
8272                    $content = 2;
8273                } else {
8274                    // - show caution flag
8275                    $reservationCautionFlag = $this->LessonSchedule->reservationCautionFlag(array(
8276                        'userId' => $userId,
8277                        'timestamp' => $this->timeDiffSecond
8278                    ));
8279
8280                    // - check reservation limit 4reservations/day
8281                    $totalReservationCounselor = $this->LessonSchedule->countUserReservationForTeacherCounselor(array(
8282                        'userId' => $userId,
8283                        'lessonDate' => $this->request->data['lessonDate'],
8284                        'timeDiffSecond' => $this->timeDiffSecond
8285                    ));
8286
8287                    // - check counselor reservations per day limit
8288                    if ($totalReservationCounselor >= 4) {
8289                        $content = 3;
8290
8291                    // - check caution flag and not yet over 20 max limit total reservation
8292                    } elseif ($reservationCautionFlag && $totalReservation < 20) {
8293                        $content = 1;
8294                    }
8295                }
8296
8297            } else {
8298                // - count total cancellations
8299                $userCancelledReservation = $this->LessonScheduleCancel->countCancelledReservation(array('userId' => $userId));
8300                if ($userCancelledReservation >= 3) {
8301                    $content = 4;
8302                }
8303
8304                // cancel in time not allowed
8305                if(!empty($this->request->data['lessonTime']) && !$content){
8306
8307                    // if time >= lesson time(server time)
8308                    if(strtotime('now') >= strtotime($this->request->data['lessonTime'])){
8309                        $content = 7;
8310                    }
8311                }
8312            }
8313            // get user counseling attended flag status
8314            $userData = $this->User->getUserData(
8315                array('User.id' => $userId),
8316                array(
8317                    'User.counseling_attended_flg',
8318                    'User.next_charge_date'
8319                ),
8320                'first'
8321            );
8322
8323            $nextChargeDate = "";
8324            if (isset($userData['User']['next_charge_date'])) {
8325                $chargeDateJP = TimezoneTable::computeTimeToUser(array(
8326                    'time' => strtotime($userData['User']['next_charge_date']),
8327                    'timestamp' => $this->timeDiffSecond
8328                ));
8329                $nextChargeDate = date('Y', $chargeDateJP) . "年" . date('m', $chargeDateJP) . "月" . date('d', $chargeDateJP) . "日";
8330            }
8331            //This will be get last records for counselor details
8332            $getLastDetails = $this->Counseling->getLastCounselingById($userId);
8333
8334            $params23 = array(
8335                'user_id' => $userId,
8336                'lesson_time' =>  $this->request->data['lessonTime'] ?? null,
8337            );
8338            $lsId = $this->LessonSchedule->counselorCheckExpiredCoin($params23);
8339
8340            // NC-8428 - check if user has user point history record
8341            $_lsId = isset($lsId['LessonSchedule']['id']) ? $lsId['LessonSchedule']['id'] : null;
8342            $pointParam = array(
8343                'log_id' => $_lsId,
8344                'user_id' => $userId,
8345                'kbn_type' => 2, // coin  use
8346                'expiration_flg' => 2,
8347                'payment_plan_id' => isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null
8348            );
8349            $isExpired = ClassRegistry::init('UsersPointHistory')->checkCoinExpiration($pointParam);
8350
8351            return json_encode(array(
8352                'status' => 'OK',
8353                'content' => $content,
8354                'lastDetails' => $getLastDetails,
8355                'cancelCount' => $userCancelledReservation,
8356                'displayNotice' => (isset($userData['User']['counseling_attended_flg'])) ? $userData['User']['counseling_attended_flg'] : 0,
8357                'nextChargeDate' => $nextChargeDate,
8358                'isExpired' => $isExpired,
8359            ));
8360        } else {
8361            return json_encode(array(
8362                'status' => 'NG',
8363                'content' => 0,
8364                'cancelCount' => 0,
8365                'displayNotice' => 0
8366            ));
8367        }
8368    }
8369
8370    /**
8371     * @api {post} /user/waiting/avatarLimit avatarLimit()
8372     * @apiName avatarLimit
8373     * @apiGroup Waiting
8374     * @apiDescription Checks the reservation and cancellation limits for avatar lessons for the authenticated user in Native Camp. It returns the status and any relevant messages or limits.
8375     *
8376     * @apiBody {String} action The action to perform (add or cancel).
8377     * @apiBody {String} teacher_avatar The ID of the avatar teacher.
8378     * @apiBody {String} [lessonDate] The date of the lesson (required for add action).
8379     * @apiBody {String} [lessonTime] The time of the lesson (required for cancel action).
8380     * 
8381     * @apiSuccess {String} status The status of the request (OK or NG).
8382     * @apiSuccess {Number} content The content of the response (0: No issues, 1: Caution flag, 2: Exceeds total reservation limit, 3: Exceeds avatar reservations per day limit, 4: Exceeds cancellation limit, 5: Beyond available days for complimentary plan, 6: Exceeds corporate light lesson limit, 7: Cancel in time not allowed).
8383     * @apiSuccess {Number} cancelCount The count of cancellations by the user.
8384     * @apiSuccess {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8385     * @apiSuccess {String} nextChargeDate The next charge date for the user.
8386     *
8387     * @apiSuccessExample {json} Success-Response:
8388     *     {
8389     *         "status": "OK",
8390     *         "content": 0,
8391     *         "cancelCount": 1,
8392     *         "displayNotice": 0,
8393     *         "nextChargeDate": "2023年12月01日"
8394     *     }
8395     *
8396     * @apiError {String} status The status of the request (NG).
8397     * @apiError {Number} content The content of the response (0: No issues).
8398     * @apiError {Number} cancelCount The count of cancellations by the user.
8399     * @apiError {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8400     *
8401     * @apiErrorExample {json} Error-Response:
8402     *     {
8403     *         "status": "NG",
8404     *         "content": 0,
8405     *         "cancelCount": 0,
8406     *         "displayNotice": 0
8407     *     }
8408     * 
8409     * @apiSampleRequest off
8410     */
8411    public function avatarLimit() {
8412        $this->autoRender = false;
8413        if ($this->request->is('ajax')) {
8414
8415            $userCancelledReservation = 0;
8416            $userId = $this->Auth->user('id');
8417            $action = $this->request->data['action'];
8418            $teacherAvatarId = $this->request->data['teacher_avatar'];
8419            $content = 0;
8420            if ($action == 'add') {
8421
8422                if (empty($this->request->data['lessonDate'])) {
8423                    return json_encode(array(
8424                        'status' => 'NG',
8425                        'content' => 0
8426                    ));
8427                }
8428
8429                // if complimentary user plan
8430                $user = $this->sharedUserData['User'];
8431                if (isset($user['payment_plan_id']) && $user['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
8432                    $this->loadModel('ComplimentaryCode');
8433                    $user['lessonTime'] = date('Y-m-d', strtotime($this->request->data['lessonDate']));
8434                    if (!$result = $this->ComplimentaryCode->validateUserComplimentaryPlan($user)) {
8435                        // set beyond available days to true
8436                        return json_encode(array('status' => 'OK', 'content' => 5));
8437                    }
8438                }
8439
8440                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
8441
8442                // NC-7361 - corporate light
8443                if (isset($corporateType) && $corporateType == Configure::read('corporate_type.light')) {
8444                    if (ClassRegistry::init('Corporate')->corpLightLessonMaxLimit(array("user_id" => $userId))) {
8445                        return json_encode(array('status' => 'OK', 'content' => 6));
8446                    }
8447                }
8448
8449                // - get total reservation
8450                $totalReservation = $this->LessonSchedule->countUserTotalReservation(array('userId' => $userId));
8451
8452                // - check if total reservation exceeds limit
8453                if ($totalReservation >= Configure::read("maximum_number_of_total_reservation")) {
8454                    $content = 2;
8455                } else {
8456                    // - show caution flag
8457                    $reservationCautionFlag = $this->LessonSchedule->reservationCautionFlag(array(
8458                        'userId' => $userId,
8459                        'timestamp' => $this->timeDiffSecond
8460                    ));
8461
8462                    // - check reservation limit 4reservations/day
8463                    $totalReservationAvatar = $this->LessonSchedule->countUserReservationForTeacherAvatar(array(
8464                        'avatar_id' => $teacherAvatarId,
8465                        'userId' => $userId,
8466                        'lessonDate' => $this->request->data['lessonDate'],
8467                        'timeDiffSecond' => $this->timeDiffSecond
8468                    ));
8469
8470                    // - check avatar reservations per day limit
8471                    if ($totalReservationAvatar >= 4) {
8472                        $content = 3;
8473
8474                    // - check caution flag and not yet over 20 max limit total reservation
8475                    } elseif ($reservationCautionFlag && $totalReservation < 20) {
8476                        $content = 1;
8477                    }
8478                }
8479
8480            } else {
8481                // - count total cancellations
8482                $userCancelledReservation = $this->LessonScheduleCancel->countCancelledReservation(array('userId' => $userId));
8483                if ($userCancelledReservation >= 3) {
8484                    $content = 4;
8485                }
8486
8487                // cancel in time not allowed
8488                if(!empty($this->request->data['lessonTime']) && !$content){
8489
8490                    // if time >= lesson time(server time)
8491                    if(strtotime('now') >= strtotime($this->request->data['lessonTime'])){
8492                        $content = 7;
8493                    }
8494                }
8495            }
8496            // get user
8497            $userData = $this->User->getUserData(
8498                array('User.id' => $userId),
8499                array(
8500                    'User.next_charge_date'
8501                ),
8502                'first'
8503            );
8504
8505            $nextChargeDate = "";
8506            if (isset($userData['User']['next_charge_date'])) {
8507                $chargeDateJP = TimezoneTable::computeTimeToUser(array(
8508                    'time' => strtotime($userData['User']['next_charge_date']),
8509                    'timestamp' => $this->timeDiffSecond
8510                ));
8511                $nextChargeDate = date('Y', $chargeDateJP) . "年" . date('m', $chargeDateJP) . "月" . date('d', $chargeDateJP) . "日";
8512            }
8513
8514            return json_encode(array(
8515                'status' => 'OK',
8516                'content' => $content,
8517                'cancelCount' => $userCancelledReservation,
8518                'displayNotice' => 0,
8519                'nextChargeDate' => $nextChargeDate
8520            ));
8521        } else {
8522            return json_encode(array(
8523                'status' => 'NG',
8524                'content' => 0,
8525                'cancelCount' => 0,
8526                'displayNotice' => 0
8527            ));
8528        }
8529    }
8530
8531    /**
8532     * @api {post} /user/waiting/checkCounselingReservationNow checkCounselingReservationNow()
8533     * @apiName checkCounselingReservationNow
8534     * @apiGroup Waiting
8535     * @apiDescription Checks if the user has a reserved counseling session at the current time. It returns the status of the reservation and the teacher's information if available.
8536     *
8537     * @apiBody {String} userId The ID of the user.
8538     * 
8539     * @apiSuccess {String} status The status of the request (OK or NG).
8540     * @apiSuccess {Number} [state] The state of the counseling reservation (1: No reserved counseling, 2: Reserved counseling and teacher is on standby, 3: Reserved counseling and teacher is not on standby).
8541     * @apiSuccess {String} [teacher_id] The ID of the teacher (if state is 2).
8542     * @apiSuccess {String} [chat_hash] The chat hash of the lesson (if state is 2).
8543     *
8544     * @apiSuccessExample {json} Success-Response:
8545     *     {
8546     *         "status": "OK",
8547     *         "state": 2,
8548     *         "teacher_id": "123",
8549     *         "chat_hash": "example_chat_hash"
8550     *     }
8551     *
8552     * @apiError {String} status The status of the request (NG).
8553     *
8554     * @apiErrorExample {json} Error-Response:
8555     *     {
8556     *         "status": "NG"
8557     *     }
8558     * 
8559     * @apiSampleRequest off
8560     */
8561    public function checkCounselingReservationNow() {
8562        $this->autoRender = false;
8563        $data = $this->request->data;
8564        $result = array('status' => 'OK');
8565
8566        if (empty($data['userId'])) {
8567            return json_encode(array(
8568                'status' => 'NG'
8569            ));
8570        }
8571
8572        if ($this->request->is('ajax')) {
8573            //target lesson schedule start time
8574            $minutes = date('i');
8575            if ($minutes >= 0 && $minutes < 26) {
8576                $lessonTime = date('Y-m-d H:00:00');
8577            } elseif ($minutes >= 30 && $minutes < 56) {
8578                $lessonTime = date('Y-m-d H:30:00');
8579            } else {
8580                // - [1] if user has no reserved counseling
8581                $result['state'] = 1;
8582                return json_encode($result);
8583            }
8584
8585            // - check ongoing lesson
8586            $counselingInfo = $this->LessonSchedule->find('first', array(
8587                    'fields' => array(
8588                        'LessonSchedule.id',
8589                        'LessonOnair.teacher_id',
8590                        'LessonOnair.chat_hash'
8591                    ),
8592                    'conditions' => array(
8593                        'LessonSchedule.lesson_time' => $lessonTime,
8594                        'LessonSchedule.user_id' => $data['userId']
8595                    ),
8596                    'joins' => array(
8597                        array(
8598                            'type' => 'LEFT',
8599                            'table' => 'lesson_onairs',
8600                            'alias' => 'LessonOnair',
8601                            'conditions' => array('LessonSchedule.teacher_id = LessonOnair.teacher_id AND LessonOnair.connect_flg = 1')
8602                        ),
8603                        array(
8604                            'type' => 'INNER',
8605                            'table' => 'teachers',
8606                            'alias' => 'Teacher',
8607                            'conditions' => array('Teacher.id = LessonOnair.teacher_id AND Teacher.counseling_flg = 1')
8608                        )
8609                    ),
8610                    'recursive' => -1
8611                )
8612            );
8613
8614            // - [1] if user has no reserved counseling
8615            if (empty($counselingInfo)) {
8616                $result['state'] = 1;
8617                return json_encode($result);
8618            }
8619
8620            // - [2] if user has reserved counseling and teacher is on standby
8621            if (!empty($counselingInfo['LessonOnair']['chat_hash'])) {
8622                $result['state'] = 2;
8623                $result['teacher_id'] = $counselingInfo['LessonOnair']['teacher_id'];
8624                $result['chat_hash'] = $counselingInfo['LessonOnair']['chat_hash'];
8625                return json_encode($result);
8626
8627            // - [3] if user has reserved counseling and teacher is not on standby
8628            } elseif (empty($counselingInfo['LessonOnair']['chat_hash'])) {
8629                $result['state'] = 3;
8630                return json_encode($result);
8631            } else {
8632                $result['state'] = 1;
8633                return json_encode($result);
8634            }
8635
8636        } else {
8637            return json_encode(array(
8638                'status' => 'NG'
8639            ));
8640        }
8641    }
8642
8643
8644    //Retrieves the details of a specific teacher for the mobile view in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
8645    public function spDetail($teacherId) {
8646        if (!intval($teacherId)) {
8647            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
8648        }
8649
8650        // NJ-10759: redirect to mypage if teacher detail sp is counseling and access from teacher mobapp
8651        // redirect if counseling teacher
8652        $counselorParams = array(
8653            'type' => 'count',
8654            'args' => array(
8655                'conditions' => array(
8656                    'id' => $teacherId,
8657                    'counseling_flg' => 1
8658                ),
8659                'recursive' => -1
8660            )
8661        );
8662
8663
8664        // - NC-3802: redirect to mypage if counselor teacher
8665        if ($this->Teacher->getTeachers($counselorParams)) {
8666            return $this->redirect(myTools::getUrl() . '/user/mypage');
8667        }
8668
8669        //fetch teacher data
8670        $data = $this->Teacher->findById($teacherId);
8671
8672        //no teacher data
8673        if (!$data) {
8674            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
8675        }
8676
8677        // //check company ip and if the teacher is stealth on redirect to teacher list
8678        // if (!myTools::checkCompanyIP($_SERVER['REMOTE_ADDR']) && $data['Teacher']['stealth_flg']) {
8679        //     return $this->redirect(array('controller' => 'SpTeacher', 'action' => 'index'));
8680        // }
8681
8682        //redirect if withdrawn teacher
8683        if ($data['Teacher']['status'] <> 1  || $data['Teacher']['inactive_flg'] == 1) {
8684            return $this->redirect(myTools::geturl() . '/waiting');
8685        }
8686
8687        if(in_array($data['Teacher']['rank_coin_id'], $this->blockMemberSettings)) {
8688            return $this->redirect('/waiting');
8689        }
8690
8691        // - check if blocked student
8692        if (BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) {
8693            return $this->redirect('/waiting');
8694        }
8695
8696        // - NC-7031: redirect avatar
8697        $avatarData = $this->isAvatar($teacherId);
8698
8699        if ($avatarData) {
8700            $getAId = $avatarData;
8701            return $this->redirect('/avatar_detail/'.$getAId);
8702        }
8703
8704        //lesson onair
8705        $onair1 = $this->LessonOnair->find('first', array(
8706            'fields' => array('LessonOnair.status', 'LessonOnair.connect_flg'),
8707            'conditions' => array('LessonOnair.teacher_id' => $data['Teacher']['id'])
8708        ));
8709
8710        //teacher_status if login or break
8711        $teacherStatus1 = $this->TeacherStatus->find('first', array(
8712            'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1'),
8713            'conditions' => array('TeacherStatus.teacher_id' => $data['Teacher']['id']))
8714            );
8715        // get counrty details
8716        $teacherCountryDetails = $this->CountryCode->find('first', array(
8717            'fields' => array('country_name', 'nationality', 'code'),
8718            'conditions' => array('CountryCode.id' => $data['Teacher']['homeland2']))
8719            );
8720
8721        //get own reviews
8722        $selfReviews = array();
8723        $selfLessonCount = 0;
8724        $selfLessonNow = 0;
8725        $selfReservation = 0;
8726        $daysPast = 0;
8727        $userId = $this->Auth->user('id');
8728        $this->set('userId', $userId);
8729        if ($userId) {
8730            $this->set('user_lang',  $this->sharedUserData['User']['native_language2']);
8731            $selfReviews = $this->getUserReviews($userId, $teacherId);
8732            $userLessonDetail = $this->LessonOnairsLog->getUserLessonCount($userId, $teacherId);
8733            $selfLessonNow = $userLessonDetail['lessonCount'];
8734            $selfReservation = $userLessonDetail['reserveCount'];
8735            $selfLessonCount = $selfLessonNow + $selfReservation;
8736            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
8737        }
8738
8739        if (!empty($onair1)) {
8740            $onair = new LessonOnairTable($onair1['LessonOnair']);
8741        } elseif (!empty($teacherStatus1)) {
8742            $onair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
8743        } else {
8744            $onair = 0;
8745        }
8746
8747        $rateBreakdown = null;
8748        $rating = $this->UsersClassEvaluation->getRatings($teacherId, true);
8749        if ($rating) {
8750            $rates = new UsersClassEvaluationTable($rating['UsersClassEvaluation']);
8751            $rateBreakdown = new UsersClassEvaluationTable($rating['TeacherWeeklyRating']);
8752        }
8753
8754        $this->set('onair', $onair);
8755        $this->set('teacher_id', $teacherId);
8756
8757        $teacher = new TeacherTable($data['Teacher']);
8758        $country = new TeacherTable($teacherCountryDetails['CountryCode']);
8759        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
8760        $meta_desc = preg_replace('/\s+/', ' ', trim($teacher->getMetaMobile()));
8761        $this->set('teacher', $teacher);
8762
8763        # get weekly rating
8764        $get_weekly_rating = $this->UsersClassEvaluation->getRatings($teacherId,true);
8765        if ($get_weekly_rating['TeacherWeeklyRating']['averageRate']) {
8766            $get_weekly_rating['TeacherWeeklyRating']['ratings'] = $get_weekly_rating['TeacherWeeklyRating']['averageRate'];
8767        }
8768
8769        //number of lesson
8770        $lessonCount = (int)$teacher->lesson_count;
8771
8772        // Translate and save translated data
8773        $globalTranslate = TeacherTable::translate(array(
8774            'id' => $teacher->id,
8775            'lang'=> isset($this->localizeDir) ? $this->localizeDir : $this->lang_iso,
8776            'controller' => static::class
8777        ));
8778        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
8779        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
8780        $this->set('message', $translatedMessageTranslation);
8781        $this->set('intro', $translatedThirdppTranslation);
8782
8783        // NJ-32759
8784        $userLang = isset($this->localizeDir) ? $this->localizeDir : Configure::read('english_language_id');
8785        $languageIds = $this->CountryCode->getLanguageList(['field'=>'iso_639_1']);
8786        $getCRData = $this->Teacher->getCountryResidenceData($teacherId, $userLang, 'first', $languageIds);
8787        $residenceData = $this->getResidenceData($getCRData);
8788        $this->set('residenceData',$residenceData);
8789        $this->set('residenceFlg',$residenceData['countryFlag']);
8790
8791        // get teacher strength feature items
8792        $strengthItemsParams = array(
8793            'teacherId' => $teacherId,
8794            'type' => 0,
8795            'langId' => $this->CountryCode->getUserLanguageId($this->localizeDir),
8796            'limit' => 3
8797        );
8798        $showRating = $teacher->getReviewOption($teacher->rank_coin_id);
8799        $this->set('showRating', $showRating);
8800        $strengthItems = $this->TeacherFeatureRating->getFeatureRatingItems($strengthItemsParams);
8801        $this->set('strengthItems', $strengthItems);
8802        
8803        // - prepare head text
8804        $headTextWD = $pageTitleWD = $teacher->name;
8805        $metaDescWD = "";
8806        if ($this->localizeDir == Configure::read('default.user_language')) {
8807            $headTextWD .= '('.$teacher->jp_name.')';
8808            $pageTitleWD .=  '('.$teacher->jp_name.')';
8809            //$metaDescWD .= '('.$teacher->jp_name.')';
8810        }
8811
8812        //find the selfintro 
8813        $TeacherTable = new TeacherTable($teacher);
8814        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
8815        $_userSelfIntro = strip_tags($_userSelfIntro); 
8816
8817        //prepare meta image 
8818        $_teacherImgUrl = $teacher->getImageUrl();
8819
8820        //check if teacher has no image 
8821        if (empty($teacher->image_url) || !$teacher->image_url) {
8822            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
8823            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
8824        }
8825
8826        $headTextWD .= '&ensp;' . __d('waiting', 'レッスン').':'.$lessonCount.__d('waiting', '回');
8827        $pageTitleWD .= '&ensp;' . sprintf(__d('waiting', 'レッスン:%s回 - 講師詳細 | オンライン英会話のネイティブキャンプ'), $lessonCount);
8828        //$metaDescWD .= '講師の紹介ページです。'.$teacher->getMetaDescription();
8829        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
8830
8831
8832        // NJ-3786 textbook teacher recommendation
8833        $curDate = date('Y-m-d');
8834        $userId = $this->Auth->user('id') ? $this->Auth->user('id') : null;
8835        $txtTeacherRecommendlimit = 10;
8836        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
8837        $endDate = date('Y-m-d',strtotime('-1 day' ,strtotime($curDate)));
8838        $beginDate = date('Y-m-d',strtotime('-1 month' ,strtotime($curDate)));
8839
8840        if( $userId ) {
8841            $teacherObj = new TeacherTable($data['Teacher']);
8842            $lastBookUsedData = $this->UsersTextbookInfo->getCurrentTextbookAndBadgeData( array( 'user_id' => $userId ) );
8843            $textbookCategoryId = $lastBookUsedData['category_id'];
8844            $textbookBadge = $lastBookUsedData['textbook_badge'];
8845            $paramsArr = array(
8846                'user_id' => $userId,
8847                'begin_date' => $beginDate,
8848                'end_date' => $endDate,
8849                'textbook_category' => $textbookCategoryId,
8850                'textbook_badge' => $textbookBadge,
8851                'limit' => $txtTeacherRecommendlimit,
8852                'user_data' => $userData,
8853                'exclude_teacher_id' => $teacherId
8854            );
8855
8856            $teacherTextbookStatData = $this->TeacherTextbookStat->fetchTextbookTeacherRatingData($paramsArr);
8857            if( $teacherTextbookStatData ) {
8858                $dataList = $this->arrangeTeacherRecommendList( array( 
8859                        'user_id' => $userId,
8860                        'data' => $teacherTextbookStatData,
8861                        'category_id' => $textbookCategoryId,
8862                        'user_data' => $userData
8863                    ) 
8864                );
8865                $this->set('textbookTeacherData', $dataList);
8866            }
8867
8868            // - user callan unli option flg
8869            $callan_option = isset($this->sharedUserData['User']['callan_option']) ? $this->sharedUserData['User']['callan_option'] : 0;
8870
8871            // - user native unli option flg
8872            $native_option = isset($this->sharedUserData['User']['native_option']) ? $this->sharedUserData['User']['native_option'] : 0;
8873
8874            $can_use_callan_option = 0;
8875            if($callan_option || $native_option) {
8876                $can_use_callan_option = 1;
8877            }
8878
8879            $this->set('can_use_callan_option', $can_use_callan_option);
8880
8881            // - teacher callan unli option flg
8882            $unlimited_option_flag = $this->HomeBasedRankBasicAmount->getUnlimitedOptionFlg($teacherObj->current_rank_id);
8883            $callan_option_teacher_flg = (isset($unlimited_option_flag['callan_unlimited_option_flg']) && $unlimited_option_flag['callan_unlimited_option_flg']) ? $unlimited_option_flag['callan_unlimited_option_flg'] : 0; 
8884            $this->set('callan_option_teacher_flg', $callan_option_teacher_flg);
8885            
8886            // - check if has callan badge
8887            $teacher_callan_badge = ClassRegistry::init('TeacherBadge')->checkCallanBadges(array('teacher_id' => $teacherId));
8888            $this->set('teacher_callan_badge', $teacher_callan_badge);
8889        }
8890
8891        // - set page meta information
8892        $this->set('headtext', $headTextWD);
8893        $this->set('title_for_layout', $pageTitleWD);
8894        $this->set('meta_description', $metaDescWD);
8895        $this->set('lessonCount', $lessonCount);
8896        $this->set('country', $country);
8897        $this->set('rateBreakdown', $rateBreakdown);
8898        $this->set('selfReviews', $selfReviews);
8899        $this->set('selfLessonCount', $selfLessonCount);
8900        $this->set('daysPast', $daysPast);
8901        $this->set('meta_teacher_img',$_teacherImgUrl);
8902
8903        # get studydapuri textbooks
8904        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
8905        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
8906            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
8907            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
8908        } elseif ($this->isStudySapuriTosUser) {
8909            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
8910        } else {
8911            $exCat = Configure::read('all_sapuri_textbook_category_types');
8912            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
8913        }
8914
8915        $return = TeacherDetailTable::teacherIntroDetails($data, $this->localizeDir,$this->Auth->loggedIn(),$conArr);
8916
8917        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
8918        $teacherOccupation = ClassRegistry::init('TeacherOccupationDetail')->getTeacherOccupationDetails($teacherId);
8919        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
8920        $lessonHistories = $this->getLessonHistory(true, $teacherId);
8921        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => array('UsersFavorite.teacher_id' => $teacherId)));
8922
8923        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacherId);
8924        $coinParams =  array(
8925            'current_rank_id' => $teacherCurrentRankId,
8926            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
8927            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
8928            'student_native_option' => $userData->native_option,
8929            'home_flg' => $teacher->home_flg,
8930            'counseling_flg' => $teacher->counseling_flg,
8931            'avatar_parent_flg' => $teacher->avatar_parent_flg,
8932            'avatar_flg' => $teacher->avatar_flg,
8933            'native_speaker_flg' => $teacher->native_speaker_flg
8934        );
8935
8936        // get teacher coin settings
8937        $teacherReserveCoin = $this->Teacher->getTeacherReserveCoin($coinParams);
8938        $teacherCoinData = [];
8939        if($teacherReserveCoin){
8940            // set teacher reservation coin
8941            $teacherCoinData = [
8942                'lesson_now' => (int) $teacherReserveCoin['lesson_coin'],
8943                'reserve_coin' => (int) $teacherReserveCoin['reserve_coin'],
8944                'reserve_coin_before_discount' => (int) $teacherReserveCoin['reserve_coin_before_discount'],
8945                'reserve_coin_with_op' => isset($teacherReserveCoin['display_native_option_amount_flg']) ? (int) $teacherReserveCoin['display_native_option_amount_flg'] : false,
8946                'displayNativeOptionAmountFlg' =>  isset($teacherReserveCoin['reserve_coin_with_op']) ? (int) $teacherReserveCoin['reserve_coin_with_op'] : null,
8947                'teacherCoinWithOp' => $teacherReserveCoin['reserve_coin_with_op'],
8948                'teacherCoinBeforeDiscount' => $teacherReserveCoin['reserve_coin_before_discount']
8949            ];
8950            $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoinData['reserve_coin'] / 2 : $teacherCoinData['reserve_coin'];
8951            $teacherCoinData['callan_coin'] = (int) $callanCoin;
8952            $teacherCallanDiscount = $teacher->getCallanHalfPrice();
8953
8954            $sapuriCoin = 0;
8955            if ($this->isStudySapuriUser) {
8956                $teacherParams = array(
8957                    'teacher_id' => $teacher->id,
8958                    'current_rank_id' => $teacherCurrentRankId
8959                );
8960                $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
8961            }
8962
8963        }
8964
8965        $OS = myTools::getOSFromUA($_SERVER['HTTP_USER_AGENT'], TRUE);
8966
8967        // NJ-20069 - feature tag lists
8968        $feature_tags_list = [
8969            "new" => "新人講師",
8970            "best_free_talk" => "フリートークが得意",
8971            "good_in_teaching_textbook" => "教材レッスンが得意",
8972            "suitable_for_intermediate_or_advance_students" => "中/上級者向き",
8973            "have_many_beginner_students" => "初級者向き",
8974            "suitable_for_children" => "キッズ向き",
8975            "suitable_for_senior" => "シニア向き",
8976            "good_grammar_and_vocabulary" => "文法・ボキャブラリー",
8977            "good_for_first_timer" => "体験レッスン向き",
8978            "pronunciation" => "発音"
8979        ];
8980        $data = $this->User->findById($userId);
8981
8982        // NJ-17264
8983        $titleThresholdData = [];
8984
8985        $this->TitleThresholdTeacher->openDBReplica();
8986        $titleThresholdData = $this->TitleThresholdTeacher->find('first', [
8987            'fields'=>'TitleThresholdTeacher.title_type',
8988            'conditions' => array(
8989                'TitleThresholdTeacher.teacher_id' => $teacherId,
8990                'TitleThresholdTeacher.type = 1'
8991            ),
8992            'recursive' => -1
8993        ]);
8994        $this->TitleThresholdTeacher->closeDBReplica();
8995        // NJ-17264
8996
8997        $this->set('user',$data);
8998        $this->set('userOS', $OS);
8999        $this->set('localizeDir', $this->localizeDir);
9000        $this->set('teacherCoinData', $teacherCoinData);
9001        $this->set('lessonHistories', $lessonHistories);
9002        $this->set('teacherRates', $reserveAndCancel);
9003        $this->set('teacherOccupation', $teacherOccupation);
9004        $this->set('series', $return['series']);
9005        $this->set('feature', $return['feature']);
9006        $this->set('historyMonth', $historyMonth);
9007        $this->set('historyYear', $historyYear);
9008        $this->set('weekly_ratings', $get_weekly_rating['TeacherWeeklyRating']);
9009        $this->set('teacherId', $teacherId);
9010        $this->set('feature_tags_list', $feature_tags_list);
9011        $this->set('features', $this->teacherFeatures(true, $teacherId));
9012        $this->set('stusapLessonCount', (int) $teacher->stusap_lesson_count + (int) $teacher->stasapu_tos_lesson_count);
9013        $this->set('favoriteCount', $favoriteCount);
9014        $this->set('sapuriCoin', $sapuriCoin);
9015        $this->set('teacherCallanDiscount', empty($teacherCallanDiscount)? 0: $teacherCallanDiscount);
9016        $this->set('title_type', isset($titleThresholdData['TitleThresholdTeacher']['title_type']) ? $titleThresholdData['TitleThresholdTeacher']['title_type'] : 0);
9017
9018        $this->layout = 'mobile';
9019        $this->render('/Mobile/Teacher/detail');
9020    }
9021
9022
9023    //Retrieves the details of a specific avatar teacher for the mobile view in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
9024    public function spAvatarDetail($teacherId) {
9025        if (!intval($teacherId)) {
9026            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
9027        }
9028
9029        //fetch teacher data
9030        $data = $this->Teacher->findById($teacherId);
9031
9032        //no teacher data
9033        if (!$data) {
9034            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
9035        }
9036
9037        // //check company ip and if the teacher is stealth on redirect to teacher list
9038        // if (!myTools::checkCompanyIP($_SERVER['REMOTE_ADDR']) && $data['Teacher']['stealth_flg']) {
9039        //     $this->redirect(array('controller' => 'SpTeacher', 'action' => 'index'));
9040        // }
9041
9042        if (BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) {
9043            return $this->redirect('/waiting');
9044        }
9045
9046        //lesson onair
9047        $onair1 = $this->LessonOnair->find('first', array(
9048            'fields' => array('LessonOnair.status', 'LessonOnair.connect_flg'),
9049            'conditions' => array('LessonOnair.teacher_id' => $data['Teacher']['id'])
9050            ));
9051
9052        //number of reservation
9053
9054        //teacher_status if login or break
9055        $teacherStatus1 = $this->TeacherStatus->find('first', array(
9056            'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1'),
9057            'conditions' => array('TeacherStatus.teacher_id' => $data['Teacher']['id']))
9058            );
9059        // get counrty details
9060        $teacherCountryDetails = $this->CountryCode->find('first', array(
9061            'fields' => array('country_name', 'nationality', 'code'),
9062            'conditions' => array('CountryCode.id' => $data['Teacher']['homeland2']))
9063            );
9064
9065        //get own reviews
9066        $selfReviews = array();
9067        $selfLessonCount = 0;
9068        $selfLessonNow = 0;
9069        $selfReservation = 0;
9070        $daysPast = 0;
9071        $userId = $this->Auth->user('id');
9072        if ($userId) {
9073            $this->set('user_lang',  $this->sharedUserData['User']['native_language2']);
9074            $selfReviews = $this->getUserReviews($userId, $teacherId);
9075            $userLessonDetail = $this->LessonOnairsLog->getUserLessonCount($userId, $teacherId);
9076            $selfLessonNow = $userLessonDetail['lessonCount'];
9077            $selfReservation = $userLessonDetail['reserveCount'];
9078            $selfLessonCount = $selfLessonNow + $selfReservation;
9079            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
9080        }
9081
9082        if (!empty($onair1)) {
9083            $onair = new LessonOnairTable($onair1['LessonOnair']);
9084        } elseif (!empty($teacherStatus1)) {
9085            $onair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
9086        } else {
9087            $onair = 0;
9088        }
9089
9090
9091        $this->set('onair', $onair);
9092        $this->set('teacher_id', $teacherId);
9093
9094        $teacher = new TeacherTable($data['Teacher']);
9095        $country = new TeacherTable($teacherCountryDetails['CountryCode']);
9096        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
9097        $meta_desc = preg_replace('/\s+/', ' ', trim($teacher->getMetaMobile()));
9098        $this->set('teacher', $teacher);
9099
9100        # get weekly rating
9101        $get_weekly_rating = $this->UsersClassEvaluation->getAvatarRatings($teacherId);
9102        //number of lesson
9103        $lessonCount = (int)$teacher->lesson_count;
9104
9105        //number of lesson for all child accounts
9106        $lessonCount = $this->LessonOnairsLog->countTeacherLessons(['teacherId' => $teacherId, 'avatar' => 1]);
9107
9108        // Translate and save translated data
9109        $globalTranslate = TeacherTable::translate(array(
9110            'id' => $teacher->id,
9111            'lang'=> isset($this->localizeDir) ? $this->localizeDir : $this->lang_iso,
9112            'controller' => static::class
9113        ));
9114        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
9115        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
9116        $this->set('message', $translatedMessageTranslation);
9117        $this->set('intro', $translatedThirdppTranslation);
9118
9119        // - prepare head text
9120        $headTextWD = $pageTitleWD  = $teacher->name;
9121        $metaDescWD = "";
9122
9123        //find the selfintro 
9124        $TeacherTable = new TeacherTable($teacher);
9125        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
9126        $_userSelfIntro = strip_tags($_userSelfIntro); 
9127
9128        if ($this->localizeDir == Configure::read('default.user_language')) {
9129            $headTextWD .= '('.$teacher->jp_name.')';
9130            $pageTitleWD .=  '('.$teacher->jp_name.')';
9131            //$metaDescWD .= '('.$teacher->jp_name.')';
9132        }
9133        $headTextWD .= '&ensp;' . __d('waiting', 'レッスン').':'.$lessonCount.__d('waiting', '回');
9134        $pageTitleWD .= '&ensp;' . sprintf(__d('waiting', 'レッスン:%s回 - 講師詳細 | オンライン英会話のネイティブキャンプ'), $lessonCount);
9135        //$metaDescWD .= '講師の紹介ページです。'.$teacher->getMetaDescription();
9136        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
9137
9138        //prepare meta image 
9139        $_teacherImgUrl = $teacher->getImageUrl();
9140
9141        //check if teacher has no image 
9142        if (empty($teacher->image_url) || !$teacher->image_url) {
9143            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
9144            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
9145        }
9146
9147
9148        // - set page meta information
9149        $this->set('headtext', $headTextWD);
9150        $this->set('title_for_layout', $pageTitleWD);
9151        $this->set('meta_description', $metaDescWD);
9152        $this->set('lessonCount', $lessonCount);
9153        $this->set('country', $country);
9154        //$this->set('rateBreakdown', $rateBreakdown);
9155        $this->set('selfReviews', $selfReviews);
9156        $this->set('selfLessonCount', $selfLessonCount);
9157        $this->set('daysPast', $daysPast);
9158        $this->set('meta_teacher_img',$_teacherImgUrl);
9159    
9160
9161        # get studydapuri textbooks
9162        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
9163        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
9164            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
9165            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
9166        } elseif ($this->isStudySapuriTosUser) {
9167            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
9168        } else {
9169            $exCat = Configure::read('all_sapuri_textbook_category_types');
9170            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
9171        }
9172        
9173        $return = TeacherDetailTable::teacherIntroDetails($data, $this->localizeDir,$this->Auth->loggedIn(),$conArr);
9174
9175        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
9176        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
9177        $lessonHistories = $this->getLessonHistory(true, $teacherId);
9178        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => array('UsersFavorite.teacher_id' => $teacherId)));
9179
9180        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacherId);
9181
9182        // get user data
9183        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
9184
9185        $coinParams =  array(
9186            'current_rank_id' => $teacherCurrentRankId,
9187            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
9188            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
9189            'student_native_option' => $userData['native_option'],
9190            'home_flg' => $teacher->home_flg,
9191            'counseling_flg' => $teacher->counseling_flg,
9192            'avatar_parent_flg' => $teacher->avatar_parent_flg,
9193            'avatar_flg' => $teacher->avatar_flg,
9194            'native_speaker_flg' => $teacher->native_speaker_flg
9195        );
9196
9197        // get teacher coin settings
9198        $teacherReserveCoin = $this->Teacher->getTeacherReserveCoin($coinParams);
9199        $teacherCoinData = [];
9200        if($teacherReserveCoin){
9201            // set teacher reservation coin
9202            $teacherCoinData = [
9203                'lesson_now' => (int) $teacherReserveCoin['lesson_coin'],
9204                'reserve_coin' => (int) $teacherReserveCoin['reserve_coin'],
9205                'reserve_coin_before_discount' => (int) $teacherReserveCoin['reserve_coin_before_discount'],
9206                'displayNativeOptionAmountFlg' => isset($teacherReserveCoin['display_native_option_amount_flg']) ? (int) $teacherReserveCoin['display_native_option_amount_flg'] : false,
9207                'reserve_coin_with_op' =>  isset($teacherReserveCoin['reserve_coin_with_op']) ? (int) $teacherReserveCoin['reserve_coin_with_op'] : null,
9208                'teacherCoinWithOp' => $teacherReserveCoin['reserve_coin_with_op'],
9209                'teacherCoinBeforeDiscount' => $teacherReserveCoin['reserve_coin_before_discount']
9210            ];
9211            $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoinData['reserve_coin'] / 2 : $teacherCoinData['reserve_coin'];
9212            $teacherCoinData['callan_coin'] = (int) $callanCoin;
9213
9214            $teacherCallanDiscount = $teacher->getCallanHalfPrice();
9215
9216            $sapuriCoin = 0;
9217            if ($this->isStudySapuriUser) {
9218                $teacherParams = array(
9219                    'teacher_id' => $teacher->id,
9220                    'current_rank_id' => $teacherCurrentRankId
9221                );
9222                $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
9223            }
9224
9225        }
9226        
9227        // NJ-42412 - added feature also to spAvatarDetail (Related to NJ-20069)
9228        $feature_tags_list = [
9229            "new" => "新人講師",
9230            "best_free_talk" => "フリートークが得意",
9231            "good_in_teaching_textbook" => "教材レッスンが得意",
9232            "suitable_for_intermediate_or_advance_students" => "中/上級者向き",
9233            "have_many_beginner_students" => "初級者向き",
9234            "suitable_for_children" => "キッズ向き",
9235            "suitable_for_senior" => "シニア向き",
9236            "good_grammar_and_vocabulary" => "文法・ボキャブラリー",
9237            "good_for_first_timer" => "体験レッスン向き",
9238            "pronunciation" => "発音"
9239        ];
9240        $this->set('teacherCoinData', $teacherCoinData);
9241        $this->set('lessonHistories', $lessonHistories);
9242        $this->set('teacherRates', $reserveAndCancel);
9243        $this->set('series', $return['series']);
9244        $this->set('features', json_encode((array)$return['feature']));
9245        $this->set('historyMonth', $historyMonth);
9246        $this->set('historyYear', $historyYear);
9247        $this->set('weekly_ratings', isset($get_weekly_rating) ? $get_weekly_rating['TeacherWeeklyRating'] : 0);
9248        $this->set('teacherId', $teacherId);
9249        $this->set('avatarId', $this->isAvatar($teacherId));
9250        $this->set('favoriteCount', $favoriteCount);
9251        $this->set('feature_tags_list', $feature_tags_list);
9252        $this->set('sapuriCoin', $sapuriCoin);
9253        $this->set('teacherCallanDiscount', empty($teacherCallanDiscount)? 0: $teacherCallanDiscount);
9254        $this->layout = 'mobile';
9255        $this->render('/Mobile/Teacher/avatar_detail');
9256    }
9257
9258    /**
9259     * @api {get} /user/:language/avatar_detail/:teacherId/:highLightFlag avatar_detail()
9260     * @apiName avatar_detail
9261     * @apiGroup Waiting
9262     * @apiDescription Retrieves the details of a specific avatar teacher in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
9263     *
9264     * @apiParam {String} language The language code for the page.
9265     * @apiParam {String} teacherId The ID of the avatar teacher.
9266     * @apiParam {Boolean} [highLightFlag] Indicates whether to highlight certain elements on the page.
9267     * 
9268     * @apiSuccess {Object} teacher The teacher information.
9269     * @apiSuccess {String} teacher.id The ID of the teacher.
9270     * @apiSuccess {String} teacher.name The name of the teacher.
9271     * @apiSuccess {String} teacher.jp_name The Japanese name of the teacher.
9272     * @apiSuccess {String} teacher.image_url The URL of the teacher's image.
9273     * @apiSuccess {Object} country The country information.
9274     * @apiSuccess {String} country.country_name The name of the country.
9275     * @apiSuccess {String} country.national The nationality.
9276     * @apiSuccess {Object} timezone The timezone information.
9277     * @apiSuccess {String} timezone.timezone The timezone.
9278     * @apiSuccess {Object} tutorCategory The tutor category information.
9279     * @apiSuccess {Number} tutorCategory.coins The number of coins the teacher has.
9280     * @apiSuccess {Number} tutorCategory.limited_plan_reservation Indicates whether the teacher has a limited plan reservation (0: No, 1: Yes).
9281     * @apiSuccess {Number} timeDiff The time difference between the user's local time and the teacher's time.
9282     * @apiSuccess {Object} onair The on-air lesson information.
9283     * @apiSuccess {Number} onair.status The status of the on-air lesson.
9284     * @apiSuccess {Number} onair.connect_flg Indicates whether the teacher is connected (1: Yes, 0: No).
9285     * @apiSuccess {Number} teacherCoin The coin amount for the teacher.
9286     * @apiSuccess {Number} callanCoin The Callan coin amount for the teacher.
9287     * @apiSuccess {Number} teacherCallanDiscount The Callan discount for the teacher.
9288     * @apiSuccess {Number} lessonCount The number of lessons the teacher has conducted.
9289     * @apiSuccess {Number} historyYear The number of years the teacher has been teaching.
9290     * @apiSuccess {Number} historyMonth The number of months the teacher has been teaching.
9291     * @apiSuccess {Object} keep_memo The memo kept by the user for the teacher.
9292     * @apiSuccess {String} keep_memo.memo The memo text.
9293     * @apiSuccess {Object} reserveAndCancel The reservation and cancellation breakdown.
9294     * @apiSuccess {Number} reserveAndCancel.reserve The number of reservations.
9295     * @apiSuccess {Number} reserveAndCancel.cancel The number of cancellations.
9296     * @apiSuccess {Object} lessonHistory The lesson history of the teacher.
9297     * @apiSuccess {Number} lessonHistoryCount The count of lessons in the lesson history.
9298     * @apiSuccess {Object} latestUserLesson The latest lesson taken by the user with the teacher.
9299     * @apiSuccess {Number} latestUserLesson.id The ID of the lesson.
9300     * @apiSuccess {Number} latestUserLesson.teacher_id The ID of the teacher.
9301     * @apiSuccess {Number} latestUserLesson.user_id The ID of the user.
9302     * @apiSuccess {Number} teacherFavoriteCount The count of users who have favorited the teacher.
9303     * @apiSuccess {Number} stusapLessonCount The count of Study Sapuri lessons conducted by the teacher.
9304     * @apiSuccess {Object[]} album The album of images for the teacher.
9305     * @apiSuccess {Number} album.id The ID of the image.
9306     * @apiSuccess {String} album.image_url The URL of the image.
9307     * @apiSuccess {Object} oOnair The on-air status of the teacher.
9308     * @apiSuccess {Number} oOnair.status The status of the on-air lesson.
9309     * @apiSuccess {String} oOnair.remarks1 Remarks about the on-air lesson.
9310     * @apiSuccess {Boolean} isFav Indicates whether the user has favorited the teacher.
9311     * @apiSuccess {Number} favoriteCount The count of users who have favorited the teacher.
9312     * @apiSuccess {Object} feature The features of the teacher.
9313     * @apiSuccess {Boolean} feature.new Indicates whether the teacher is new.
9314     * @apiSuccess {Boolean} feature.best_free_talk Indicates whether the teacher is best for free talk.
9315     * @apiSuccess {Boolean} feature.good_in_teaching_textbook Indicates whether the teacher is good in teaching textbooks.
9316     * @apiSuccess {Boolean} feature.suitable_for_intermediate_or_advance_students Indicates whether the teacher is suitable for intermediate or advanced students.
9317     * @apiSuccess {Boolean} feature.have_many_beginner_students Indicates whether the teacher has many beginner students.
9318     * @apiSuccess {Boolean} isHide Indicates whether the teacher is hidden by the user.
9319     * @apiSuccess {Boolean} unsupportedBrowser Indicates whether the user's browser is unsupported.
9320     * @apiSuccess {Boolean} canReport Indicates whether the user can report the teacher.
9321     * @apiSuccess {String} reservationTextbookConnectId The ID of the textbook connect for the reservation.
9322     * @apiSuccess {Boolean} hideLimitedPlanReservation Indicates whether to hide the limited plan reservation.
9323     * @apiSuccess {Boolean} firstTimeLoggedIn Indicates whether it is the user's first time logging in.
9324     * @apiSuccess {Number} velifyCount The count of phone verification checks.
9325     * @apiSuccess {Object[]} countryCodes The list of country codes.
9326     * @apiSuccess {String} countryCodes.country_name The name of the country.
9327     * @apiSuccess {String} countryCodes.nationality The nationality.
9328     * @apiSuccess {String} countryCodes.code The country code.
9329     * @apiSuccess {Object} userCountry The country information of the user.
9330     * @apiSuccess {String} userCountry.country_name The name of the country.
9331     * @apiSuccess {String} userCountry.national The nationality.
9332     * @apiSuccess {String} userCountry.code The country code.
9333     * @apiSuccess {Boolean} paidParent Indicates whether the user is a paid parent.
9334     * @apiSuccess {String} headtext The head text for the page.
9335     * @apiSuccess {String} title_for_layout The title for the page layout.
9336     * @apiSuccess {String} meta_description The meta description for the page.
9337     * @apiSuccess {String} meta_keywords The meta keywords for the page.
9338     * @apiSuccess {String} meta_teacher_img The URL of the teacher's image for meta tags.
9339     * @apiSuccess {Object[]} selfReviews The self-reviews of the user for the teacher.
9340     * @apiSuccess {Number} selfLessonCount The count of lessons taken by the user with the teacher.
9341     * @apiSuccess {Number} daysPast The number of days past since the user's last lesson with the teacher.
9342     * @apiSuccess {Object[]} reviews The reviews of the teacher.
9343     * @apiSuccess {Number} reviews.commentCount The count of comments for the teacher.
9344     * @apiSuccess {Number} reviews.approveEvalFlag The flag indicating the approval status of the evaluations.
9345     * @apiSuccess {Number} commentCount The count of comments for the teacher.
9346     * @apiSuccess {Number} approveEvalFlag The flag indicating the approval status of the evaluations.
9347     * @apiSuccess {Object} weekly_ratings The weekly ratings of the teacher.
9348     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.id The ID of the weekly rating.
9349     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.teacher_id The ID of the teacher.
9350     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.week The week of the rating.
9351     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.year The year of the rating.
9352     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.rating The rating.
9353     * @apiSuccess {Object} translatedMessageParams The translated message parameters.
9354     * @apiSuccess {String} translatedMessageParams.translatedMessage The translated message.
9355     * @apiSuccess {Object} translatedSelfIntroductionThirdPpParams The translated self-introduction parameters.
9356     * @apiSuccess {String} translatedSelfIntroductionThirdPpParams.translatedSelfIntroductionThirdPp The translated self-introduction.
9357     * @apiSuccess {Object} translationModel The translation model.
9358     * @apiSuccess {Number} translationModel.id The ID of the translation.
9359     * @apiSuccess {Number} translationModel.teacher_id The ID of the teacher.
9360     * @apiSuccess {String} translationModel.lang The language of the translation.
9361     * @apiSuccess {String} translationModel.controller The controller of the translation.
9362     * @apiSuccess {Number} teacherCoinBeforeDiscount The coin amount for the teacher before discount.
9363     * @apiSuccess {Number} teacherCoinWithOp The coin amount for the teacher with options.
9364     * @apiSuccess {Boolean} nativeOptionFlg Indicates whether the native option is enabled.
9365     * @apiSuccess {Object} preset The preset textbook information.
9366     * @apiSuccess {String} preset.textbookConnectId The ID of the textbook connect.
9367     * @apiSuccess {String} preset.textbookCategoryTypeId The type ID of the textbook category.
9368     * @apiSuccess {String} textbookConnectId The ID of the textbook connect.
9369     * @apiSuccess {String} textbookCategoryTypeId The type ID of the textbook category.
9370     * @apiSuccess {Object[]} apologyList The list of apologies for reservation cancellations.
9371     * @apiSuccess {Number} apologyList.id The ID of the apology.
9372     * @apiSuccess {String} apologyList.apology The apology text.
9373     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
9374     * @apiSuccess {Boolean} disabledSchedule.disabled Indicates whether the schedule is disabled.
9375     * @apiSuccess {Boolean} showNoticeMaxLimit Indicates whether to show the notice for the maximum limit.
9376     * @apiSuccess {Boolean} noIndexFlgOveride Indicates whether to override the no-index flag.
9377     * @apiSuccess {Boolean} enableNextTextbookChapterButton Indicates whether to enable the next textbook chapter button.
9378     * @apiSuccess {String} chatHash The chat hash for the lesson.
9379     * @apiSuccess {Number} lessonRequestFlg The flag indicating the lesson request status.
9380     *
9381     * @apiSuccessExample {json} Success-Response:
9382     *     {
9383     *         "teacher": {
9384     *             "id": 520,
9385     *             "name": "Teacher Name",
9386     *             "jp_name": "Teacher Name",
9387     *             "image_url": "http://example.com/image.jpg"
9388     *         },
9389     *         "country": {
9390     *             "country_name": "Country Name",
9391     *             "national": "National"
9392     *         },
9393     *         "timezone": {
9394     *             "timezone": "Asia/Tokyo"
9395     *         },
9396     *         "tutorCategory": {
9397     *             "coins": 100,
9398     *             "limited_plan_reservation": 0
9399     *         },
9400     *         "timeDiff": 32400,
9401     *         "onair": {
9402     *             "status": 1,
9403     *             "connect_flg": 1
9404     *         },
9405     *         "teacherCoin": 100,
9406     *         "callanCoin": 50,
9407     *         "teacherCallanDiscount": 20,
9408     *         "lessonCount": 10,
9409     *         "historyYear": 2,
9410     *         "historyMonth": 3,
9411     *         "keep_memo": {
9412     *             "memo": "Memo"
9413     *         },
9414     *         "reserveAndCancel": {
9415     *             "reserve": 5,
9416     *             "cancel": 2
9417     *         },
9418     *         "lessonHistory": {},
9419     *         "lessonHistoryCount": 5,
9420     *         "latestUserLesson": {
9421     *             "id": 123,
9422     *             "teacher_id": 520,
9423     *             "user_id": 456
9424     *         },
9425     *         "teacherFavoriteCount": 100,
9426     *         "stusapLessonCount": 50,
9427     *         "album": [
9428     *             {
9429     *                 "id": 1,
9430     *                 "image_url": "http://example.com/image1.jpg"
9431     *             }
9432     *         ],
9433     *         "oOnair": {
9434     *             "status": 1,
9435     *             "remarks1": "Remarks"
9436     *         },
9437     *         "isFav": true,
9438     *         "favoriteCount": 200,
9439     *         "feature": {
9440     *             "new": true,
9441     *             "best_free_talk": true,
9442     *             "good_in_teaching_textbook": true,
9443     *             "suitable_for_intermediate_or_advance_students": true,
9444     *             "have_many_beginner_students": true
9445     *         },
9446     *         "isHide": false,
9447     *         "unsupportedBrowser": false,
9448     *         "canReport": true,
9449     *         "reservationTextbookConnectId": "123",
9450     *         "hideLimitedPlanReservation": false,
9451     *         "firstTimeLoggedIn": true,
9452     *         "velifyCount": 1,
9453     *         "countryCodes": [
9454     *             {
9455     *                 "country_name": "Country Name",
9456     *                 "nationality": "National",
9457     *                 "code": "Code"
9458     *             }
9459     *         ],
9460     *         "userCountry": {
9461     *             "country_name": "Country Name",
9462     *             "national": "National",
9463     *             "code": "Code"
9464     *         },
9465     *         "paidParent": false,
9466     *         "headtext": "Teacher Name",
9467     *         "title_for_layout": "Teacher Name - 講師詳細 | オンライン英会話のネイティブキャンプ",
9468     *         "meta_description": "Teacher description",
9469     *         "meta_keywords": "Teacher Name,講師,オンライン英会話,ネイティブキャンプ",
9470     *         "meta_teacher_img": "http://example.com/image.jpg",
9471     *         "selfReviews": [...],
9472     *         "selfLessonCount": 5,
9473     *         "daysPast": 10,
9474     *         "reviews": [
9475     *             {
9476     *                 "commentCount": 50,
9477     *                 "approveEvalFlag": 1
9478     *             }
9479     *         ],
9480     *         "commentCount": 50,
9481     *         "approveEvalFlag": 1,
9482     *         "weekly_ratings": {
9483     *             "TeacherWeeklyRating": {
9484     *                 "id": 123,
9485     *                 "teacher_id": 520,
9486     *                 "week": 1,
9487     *                 "year": 2021,
9488     *                 "rating": 5
9489     *             }
9490     *         },
9491     *         "translatedMessageParams": {
9492     *             "translatedMessage": "Translated message"
9493     *         },
9494     *         "translatedSelfIntroductionThirdPpParams": {
9495     *             "translatedSelfIntroductionThirdPp": "Translated self-introduction"
9496     *         },
9497     *         "translationModel": {
9498     *             "id": 123,
9499     *             "teacher_id": 520,
9500     *             "lang": "en",
9501     *             "controller": "WaitingController"
9502     *         },
9503     *         "teacherCoinBeforeDiscount": 120,
9504     *         "teacherCoinWithOp": 130,
9505     *         "nativeOptionFlg": true,
9506     *         "preset": {
9507     *             "textbookConnectId": "456",
9508     *             "textbookCategoryTypeId": "789"
9509     *         },
9510     *         "textbookConnectId": "456",
9511     *         "textbookCategoryTypeId": "789",
9512     *         "apologyList": [
9513     *             {
9514     *                 "id": 1,
9515     *                 "apology": "Apology"
9516     *             }
9517     *         ],
9518     *         "disabledSchedule": {
9519     *             "disabled": true
9520     *         },
9521     *         "showNoticeMaxLimit": false,
9522     *         "noIndexFlgOveride": false,
9523     *         "enableNextTextbookChapterButton": true,
9524     *         "chatHash": "example_chat_hash",
9525     *         "lessonRequestFlg": 1
9526     *     }
9527     *
9528     * @apiError {String} error Message indicating the error.
9529     *
9530     * @apiErrorExample {json} Error-Response:
9531     *     {
9532     *         "error": "Invalid request."
9533     *     }
9534     * 
9535     * @apiSampleRequest off
9536     */
9537    public function avatar_detail($teacherId = 520, $highLightFlag = null) {
9538        if (is_null($teacherId)) {
9539            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
9540        }
9541
9542        $this->avatarLatestLessonHistory($this->Auth->user('id'), $teacherId);
9543        //set mobile view
9544        if (myTools::defaultAction($this)) {
9545            return $this->spAvatarDetail($teacherId);
9546        }
9547
9548        $checkParams = array(
9549            'type' => 'count',
9550            'args' => array(
9551                'conditions' => array(
9552                    'id' => $teacherId,
9553                    'avatar_parent_flg' => 0
9554                ),
9555                'recursive' => -1
9556            )
9557        );
9558
9559        // - NC-3802: redirect to mypage if not avatar parent teacher
9560        if ($this->Teacher->getTeachers($checkParams)) {
9561            return $this->redirect('/mypage');
9562        }
9563
9564        if (BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) {
9565            return $this->redirect('/waiting');
9566        }
9567        //redirect to proper profile
9568        $this->checkProperProfile($teacherId);
9569
9570        $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
9571        $queryCondition = array(
9572            'fields' => array(
9573                    'TeacherRankCoin.coins',
9574                    'LessonOnair.id',
9575                    'LessonOnair.teacher_id',
9576                    'LessonOnair.user_id',
9577                    'TeacherRankCoin.limited_plan_reservation'
9578                ),
9579            'joins' => array(
9580                array(
9581                    'type' => 'LEFT',
9582                    'table' => 'teacher_rank_coins',
9583                    'alias' => 'TeacherRankCoin',
9584                    'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
9585                )
9586            ),
9587            'conditions' => array(
9588                array('Teacher.id' => $teacherId)
9589            ),
9590            'show' => 'first'
9591        );
9592
9593        $commonTeacherStatusParams = array(
9594            'page_display' => 'listTeacher',
9595            'query_conditions' => $queryCondition
9596        );
9597        $data = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
9598
9599        if (!$data) {
9600            return $this->redirect('/waiting/');
9601        }
9602
9603        //redirect if withdrawn teacher or teacher is block in NJ-43859
9604        if ($data['Teacher']['status'] <> 1  || $data['Teacher']['inactive_flg'] == 1 || in_array($data['Teacher']['rank_coin_id'], $this->blockMemberSettings)) {
9605            if ($this->Auth->loggedIn()) {
9606                return $this->redirect(myTools::geturl() . '/mypage');
9607            } else {
9608                return $this->redirect(myTools::geturl() . '/waiting');
9609            }
9610        }
9611
9612        if (isset($data['LessonOnair'])) {
9613            $tmp = (object) $data['LessonOnair'];
9614            if (!$tmp->id) {
9615                $data['LessonOnair'] = null;
9616            }
9617        }
9618
9619
9620
9621        // get teacher information
9622        $teacher = new TeacherTable($data['Teacher']);
9623
9624        $country = new TeacherTable($data['CountryCode']);
9625        $timezone = new TimezoneTable($data['Timezone']);
9626        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
9627
9628        // Avatar var
9629        $avatarTeacherId = $teacherId;
9630        $teacherName = isset($teacher->jp_name) ? $teacher->jp_name : null;
9631        $teacherNameEn = isset($teacher->name) ? $teacher->name : null;
9632        $teacherImageSrc = $teacher->getImageUrl();
9633
9634        $timeDiff = 0;
9635        if (isset($timezone->continent_id) && isset($timezone->city_eng)) {
9636            $timeDiffData = $this->Timezone->computeTimeDiff(array(
9637                'continent_id' => $timezone->continent_id,
9638                'city' => $timezone->city_eng
9639            ));
9640
9641            //
9642            if ($timeDiffData['success']) {
9643                $timeDiff = $timeDiffData['timeDiff'];
9644            }
9645        }
9646
9647        $onair = $data['LessonOnair'];
9648
9649        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacher->id);
9650        # Get teachers reservation amounts.
9651        $req_params =  array(
9652                'basic_amount_type' => 15,
9653                'current_rank_id' => $teacherCurrentRankId
9654            );
9655        $teacherCoin = $this->HomeBasedRankBasicAmountLog->getBasicAmount($req_params);
9656
9657        //
9658        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacher->id);
9659
9660        // get user data
9661        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
9662
9663        # Get teachers reservation amounts. | NJ-2038, for hb teachers only not applicable for counselor/avatar
9664        $coinParams =  array(
9665            'current_rank_id' => $teacherCurrentRankId,
9666            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
9667            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
9668            'student_native_option' => $userData['native_option'],
9669            'home_flg' => $teacher->home_flg,
9670            'counseling_flg' => $teacher->counseling_flg,
9671            'avatar_parent_flg' => $teacher->avatar_parent_flg,
9672            'avatar_flg' => $teacher->avatar_flg,
9673            'native_speaker_flg' => $teacher->native_speaker_flg
9674        );
9675
9676        // get teacher coin settings
9677        $teacherCoinData = $this->Teacher->getTeacherReserveCoin($coinParams);
9678
9679        $teacherCoinWithOp = $teacherCoinBeforeDiscount = null;
9680        $displayNativeOptionAmountFlg = false;
9681        if($teacherCoinData){
9682            // set teacher reservation coin
9683            $teacherCoin = (isset($teacherCoinData['reserve_coin']) && is_numeric($teacherCoinData['reserve_coin'])) ? $teacherCoinData['reserve_coin'] : 0;
9684            $teacherCoinBeforeDiscount = $teacherCoinData['reserve_coin_before_discount'];
9685            $teacherCoinWithOp = $teacherCoinData['reserve_coin_with_op'];
9686            $displayNativeOptionAmountFlg = $teacherCoinData['display_native_option_amount_flg'];
9687        }
9688
9689        $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoin / 2 : $teacherCoin;
9690
9691        $teacherCallanDiscount = $teacher->getCallanHalfPrice();
9692
9693        $userId = ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null;
9694
9695        //number of lesson
9696        $lessonCount = $this->LessonOnairsLog->countTeacherLessons(['teacherId' => $teacherId, 'avatar' => 1]);
9697
9698        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
9699
9700        $this->set('historyMonth',$historyMonth);
9701        $this->set('historyYear',$historyYear);
9702
9703        //NJ-20069 avatar detail changes
9704        $getKeepMemo = $this->UsersMemo->find('first', array(
9705            'fields' => array(
9706                'id',
9707                'memo'
9708            ),
9709            'conditions' => array(
9710                'user_id' => $this->Auth->user('id'),
9711                'teacher_id' => $teacherId,
9712                'type' => 0
9713            ),
9714            'order' => array('created DESC'),
9715        ));
9716
9717        $this->set('keep_memo', $getKeepMemo);
9718
9719        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
9720        $lessonHistory = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, null, "avatar");
9721        $lessonHistoryCount  = is_iterable(($lessonHistory['lessonHistory'])) ? count($lessonHistory['lessonHistory']) : 0;
9722        $latestUserLesson = ($lessonHistory['lessonHistory'][0]['LessonOnairsLog']);
9723        $teacherFavoriteCount = $this->UsersFavorite->getFavoriteCount($teacherId);
9724        $stusapLessonCount = $this->Teacher->getAvatarSapuriLessonCount($teacherId);
9725
9726        // - if has translated Category name
9727        if (isset($lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) && $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) {
9728            $lessonHistory['lessonHistory'][0]['TextbookCategory']['name'] = $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name'];
9729        }
9730
9731        $formattedLatestLessonData = "";
9732        if(!empty($latestUserLesson))
9733        $formattedLatestLessonData = date('Y-m-d',strtotime($latestUserLesson['start_time'])). " (" . date('D',strtotime($latestUserLesson['start_time'])) . ") ";
9734
9735        $this->set('lessonHistoryCount', $lessonHistoryCount);
9736        $this->set('latestUserLesson', $lessonHistory['lessonHistory'][0]);
9737        $this->set('teacherRates', $reserveAndCancel);
9738        $this->set('teacherIdCheck', $teacherId);
9739        $this->set('latestLessonData', $formattedLatestLessonData);
9740        $this->set('lessonHistory', $lessonHistory);
9741        $this->set('teacherId', $teacherId);
9742        $this->set('teacherFavoriteCount', $teacherFavoriteCount);
9743        $this->set('stusapLessonCount', $stusapLessonCount);
9744        $this->set('stusapLessonCount', (int) $teacher->stusap_lesson_count + (int) $teacher->stasapu_tos_lesson_count);
9745
9746
9747
9748        // album
9749        $this->TeacherImage->openDBReplica();
9750        $album = $this->TeacherImage->find('all', array(
9751            'fields' => array(
9752                'TeacherImage.id',
9753                'TeacherImage.teacher_id',
9754                'TeacherImage.approve_flg',
9755                'TeacherImage.is_profile',
9756                'TeacherImage.approve_required',
9757                'FileStorage.url'
9758            ),
9759            'conditions' => array(
9760                'TeacherImage.teacher_id' => $teacherId,
9761                'TeacherImage.is_profile' => 0,
9762                'OR' => array(
9763                    'OR' => array(
9764                            'TeacherImage.approve_flg' => 1,
9765                            'TeacherImage.approve_required' => 0
9766                        )
9767                    )
9768            ),
9769            'joins' => array(
9770                array(
9771                    'type' => 'INNER',
9772                    'table' => 'file_storage',
9773                    'alias' => 'FileStorage',
9774                    'conditions' => array(
9775                        'TeacherImage.file_storage_id = FileStorage.id',
9776                        'FileStorage.uploader_type = 3',
9777                        'FileStorage.uploader_id' => $teacherId
9778                    )
9779                )
9780            ),
9781            'order' => array('TeacherImage.id DESC')
9782        ));
9783        $this->TeacherImage->closeDBReplica();
9784
9785        $this->set('album', $album);
9786
9787        //lesson onair
9788        if (!empty($onair)) {
9789            $oOnair = new LessonOnairTable($onair);
9790        } else {
9791            //teacher_status if login or break
9792            $teacherStatus1 = $this->TeacherStatus->find('first', array(
9793                'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1', 'TeacherStatus.remarks2'),
9794                'conditions' => array('TeacherStatus.teacher_id' => $teacher->getId())
9795            ));
9796            if (!empty($teacherStatus1)) {
9797                $oOnair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
9798            } else {
9799                $oOnair = 0;
9800            }
9801        }
9802
9803        //favorite
9804        $where = array(
9805            'UsersFavorite.user_id'     => $this->Auth->user('id'),
9806            'UsersFavorite.teacher_id'     => $teacherId,
9807        );
9808        $isFav = $this->UsersFavorite->find('count', array('conditions' => $where));
9809        $where = array(
9810            'UsersFavorite.teacher_id'  => $teacherId,
9811        );
9812        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => $where));
9813        $where = array(
9814            'TeacherFeature.teacher_id' => $teacherId,
9815        );
9816        $feature = $this->TeacherFeature->find('first', array('conditions' => $where));
9817
9818        // NC-5897 : check if teacher was hide by user.
9819        $where = array(
9820            'user_id' => $this->Auth->user('id'),
9821            'teacher_id' => $teacherId,
9822        );
9823        $isHide = $this->BlockList->isTeacherHide($where);
9824
9825        $feature = isset($feature['TeacherFeature']) ? new TeacherFeatureTable($feature['TeacherFeature']) : new TeacherFeatureTable(array());
9826        $this->User->recursive = -1;
9827        $data = $this->User->findById($userId);
9828        $user = isset($data['User'])?$data['User']: null;
9829        $unsupportedBrowser = false;
9830        $browser =  $this->request->header('User-Agent');
9831
9832        if (preg_match('/(Edg|Edge)/i',$browser) ) {
9833            $unsupportedBrowser = false;
9834        } elseif (!preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
9835            $unsupportedBrowser = true;
9836        }
9837        $canReport = true;
9838        $reservationTextbookConnectId = "";
9839        if ($user) {
9840            $userData = new UserTable($data['User']);
9841            $userMembership = $userData->getUserMembership();
9842            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($userData->payment_plan_id);
9843            $this->set('user_lang', $userData->native_language2);
9844            // if weekly plan user
9845            $corporateUser = isset($corporateType) ? $corporateType : '';
9846
9847            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
9848            $canReport = $userData->getMembershipTypeIndex();
9849            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
9850            //NJ-24096: get last reservation textbook type
9851            $sapuriFlg = ($this->isStudySapuriTosUser || $this->isStudySapuriUser) ? true :false;
9852            $lastReservationData = LessonScheduleTable::getLastReservation($userId, $sapuriFlg);
9853
9854            if (!empty($lastReservationData['LessonSchedule']['connect_id'])) {
9855                $reservationTextbookConnectId = $lastReservationData['LessonSchedule']['connect_id'];
9856            } else {
9857                $this->User->openDBReplica();
9858                $checkUserFirstFlg = $this->LessonSchedule->field('connect_id', array('user_id' => $userId));
9859                $this->User->closeDBReplica();
9860                if (empty($checkUserFirstFlg)) {
9861                    $defaultParams = array(
9862                        'user_id' => $userId,
9863                        'lang' => $userData->native_language2
9864                    );
9865                    $defaultReservation = $this->Textbook->getDefaultReservationTBConnectId($defaultParams);
9866                    if ($defaultReservation) {
9867                        $reservationTextbookConnectId = $defaultReservation;
9868                    }
9869                }
9870            }
9871        }
9872        $this->set(compact('reservationTextbookConnectId'));
9873        $this->set('unsupportedBrowser', $unsupportedBrowser);
9874        // NC-6615 check if user can report the teacher
9875        $this->set('canReport', $canReport);
9876
9877        $hideLimitedPlanReservation = false;
9878        if ($tutorCategory->limited_plan_reservation == 0 && (isset($corporateUser) && $corporateUser ==  Configure::read('corporate_type.limited'))) {
9879            $hideLimitedPlanReservation = true;
9880        }
9881
9882        $firstTimeLoggedIn = false;
9883        if (!$user['last_login_time']) {
9884            $firstTimeLoggedIn = true;
9885        }
9886
9887        $paidParent = false;
9888
9889        $velifyCount = $this->PhoneVerifyCheckLog->find('count',array(
9890            'conditions' => array(
9891                'user_id' => $this->Auth->user('id'),
9892                'status' => 0
9893            )
9894        ));
9895
9896        $countryCodes = $this->CountryCode->find('all',array(
9897            'fields' => array(
9898                'code',
9899                'country_name'
9900            ),
9901            'order' => 'country_name ASC'
9902        ));
9903        $this->set('countryCodes',$countryCodes);
9904
9905        $userCountry['CountryCode']['country_name'] = '';
9906        $userCountry['CountryCode']['code'] = '';
9907        if(!empty($data['User']['country_code'])){
9908            $userCountry = $this->CountryCode->find('first',array(
9909                'conditions' => array(
9910                    'code' => $data['User']['country_code']),
9911                'fields' => array(
9912                    'code',
9913                    'country_name')
9914            ));
9915            if(empty($userCountry)){
9916                $userCountry['CountryCode']['code'] = '';
9917            }
9918        }
9919        $this->set('countryCodes',$countryCodes);
9920
9921        //check if user is child by checking its parent id not empty
9922        if (isset($data['User']['parent_id'])) {
9923            $paidParent = $this->User->checkPaidParent($data['User']['parent_id']);
9924        }
9925        #$lesson_count=0;
9926        // 管理者権限会員は無制限でレッスン出来る
9927        if ($user['admin_flg']=='1') {
9928            $user['charge_flg'] = 1;
9929            $lesson_count=0;
9930            $lesson_count_today = 0;
9931        }
9932
9933        if (empty($user['enquate6'])) {
9934            $user['enquate6'] = '1';
9935        }
9936
9937        if (empty($user['enquate7'])) {
9938            $user['enquate7'] = '1';
9939        }
9940        // - prepare head text
9941        $headTextWD = $pageTitleWD = $teacherNameEn;
9942        $metaDescWD = "";
9943        if ($this->localizeDir == Configure::read('default.user_language')) {
9944            $headTextWD .= '('.$teacherName.')';
9945            $pageTitleWD .=  '('.$teacherName.')';
9946            //$metaDescWD .= '('.$teacherName.')';
9947        }
9948        $pageTitleWD .= '&ensp;-&ensp;'. __d('default_pc','講師詳細 | オンライン英会話のネイティブキャンプ');
9949        //$metaDescWD .= __d('waiting','講師の紹介ページです。').$teacher->getMetaDescription();
9950
9951        //prepare meta image 
9952        $_teacherImgUrl = $teacher->getImageUrl();
9953
9954        //check if teacher has no image 
9955        if (empty($teacher->image_url) || !$teacher->image_url) {
9956            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
9957            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
9958        }
9959
9960        // - set page meta information
9961        $this->set('headtext', $headTextWD);
9962        $this->set('title_for_layout', $pageTitleWD);
9963        //$this->set('meta_description', $metaDescWD);
9964        $this->set('meta_keywords',$teacher->name.',講師,オンライン英会話,ネイティブキャンプ');
9965        $this->set('counselingFlg',$teacher->counseling_flg);
9966        $this->set('meta_teacher_img',$_teacherImgUrl);
9967        //get own reviews
9968        $selfReviews = array();
9969        $selfLessonCount = 0;
9970        $daysPast = 0;
9971        if ($userId) {
9972            $selfReviews = $this->getUserReviews($userId, $teacherId);
9973            $userLessonDetail = $this->LessonOnairsLog->getUserLessonCount($userId, $teacherId);
9974            $selfLessonNow = $userLessonDetail['lessonCount'];
9975            $selfReservation = $userLessonDetail['reserveCount'];
9976            $selfLessonCount = $selfLessonNow + $selfReservation;
9977            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
9978        }
9979        //reservation and cancellation breakdown
9980        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
9981
9982        $options = $this->Auth->user('id') ? array('userId' => $this->Auth->user('id')) : array();
9983        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir,true);
9984        $options['language_id'] = $reviewLanguage[0];
9985        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
9986        $options['avatar'] = 1;
9987
9988        $userTable = new UserTable($this->Auth->user());
9989        $sapuriPlan = $userTable->isStudySapuri();
9990        $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
9991        if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
9992            $options['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
9993        } else {
9994            $options['textbook_category_type_not_in'] = $sapuriTextbookType;
9995        }
9996
9997        $reviews = $this->UsersClassEvaluation->getComments($teacherId, 0, 4, $options);
9998        $commentCount = $this->UsersClassEvaluation->getCommentCount($teacherId, $options);
9999        $approveFlag = $this->UsersClassEvaluation->getApproveEvalCount($teacherId);
10000
10001        # get weekly rating
10002        $approveFlag = $this->UsersClassEvaluation->getApproveEvalCount($teacherId);
10003
10004        $get_weekly_rating = $this->UsersClassEvaluation->getAvatarRatings($teacherId);
10005        
10006        /* -- NC-5293 start -- */
10007        $this->loadModel('Translation');
10008        $translationCategories = Configure::read('translation_categories');
10009        $translateParams = array(
10010            'languageCode' => $this->lang_iso,
10011            'categoryId' => $translationCategories['teacher_message'],
10012            'messageId' => $teacher->id,
10013            'text' => $teacher->message
10014        );
10015
10016        $translatedMessageParams = $translateParams;
10017        $translateParams['categoryId'] = $translationCategories['teacher_self_introduction_third_pp'];
10018        $translateParams['text'] = $teacher->self_introduction_third_pp;
10019        $translatedSelfIntroductionThirdPpParams = $translateParams;
10020        /* -- NC-5293 end -- */
10021
10022        // Translate and save translated data
10023        $globalTranslate = TeacherTable::translate(array(
10024            'id' => $teacherId,
10025            'lang'=> isset($this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language'),
10026            'controller' => static::class
10027        ));
10028        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
10029        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
10030        $this->set('message', $translatedMessageTranslation);
10031        $this->set('intro', $translatedThirdppTranslation);
10032
10033        //find the selfintro 
10034        $TeacherTable = new TeacherTable($teacher);
10035        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
10036        $_userSelfIntro = strip_tags($_userSelfIntro);
10037
10038        //set the new meta description
10039        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
10040        $this->set('meta_description', $metaDescWD);
10041    
10042        $favIds = $isFav ? [$teacher->id] : [];
10043        $teacherFavColor = $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => $favIds]);
10044        $teacherFavsColors = $this->UsersFavoriteCategoriesTeacher->parseToHexColor([
10045            'favIds' => $favIds,
10046            'favIdsTeacherCategory' => $teacherFavColor
10047        ]);
10048        // set view vars
10049        $setData = array(
10050            'teacher' => $teacher,
10051            'onair' => $oOnair,
10052            'isFav' => $isFav,
10053            'teacherFavsColors' => $teacherFavsColors,
10054            'isHide' => $isHide,
10055            'favoriteCount' => $favoriteCount,
10056            'feature' => $feature,
10057            'tId' => $teacher->id,
10058            'user' => $user,
10059            'lessonAvailable' => isset($lessonAvailable['lessonAvailable']) ? $lessonAvailable['lessonAvailable'] : 0,
10060            'userMembership' => isset($userMembership)?$userMembership:'',
10061            'adminFlag' => isset($user['admin_flg'])?$user['admin_flg']:'0',
10062            'enquate6_options' => UserTable::getEnquate6(),
10063            'enquate7_options' => UserTable::getEnquate7(),
10064            'reviews' => $reviews,
10065            //'rates' => $rates,
10066            'approveEvalFlag' => $approveFlag,
10067            'weekly_ratings' => isset($get_weekly_rating) ? $get_weekly_rating['TeacherWeeklyRating'] : 0,
10068            'userId' => $userId,
10069            'cardAuth' => PaymentTable::checkIfCardAuth($this->Auth->user('id'), $this->Auth->user('hash16')),
10070            'teacherCoin' => empty($teacherCoin)? 0: (int)$teacherCoin,
10071            'callanCoin' => (int)$callanCoin,
10072            'teacherCallanDiscount' => empty($teacherCallanDiscount)? 0: $teacherCallanDiscount,
10073            'UserData' => $data,
10074            'userCountry' => $userCountry,
10075            'velifyCount' => $velifyCount,
10076            'firstTimeLoggedIn' => $firstTimeLoggedIn,
10077            //'rateBreakdown' => $rateBreakdown,
10078            'selfReviews' => $selfReviews,
10079            'selfLessonCount' => $selfLessonCount,
10080            'daysPast' => $daysPast,
10081            'reserveAndCancel' => $reserveAndCancel,
10082            'isLoggedIn' => $this->Auth->loggedIn(),
10083            'country' => $country,
10084            'timeDiff' => $timeDiff,
10085            'corporateId' => !empty($data['User']['corporate_id']) ? $data['User']['corporate_id'] : $this->Auth->user('corporate_id'),
10086            'translatedMessageParams' => $translatedMessageParams,
10087            'translatedSelfIntroductionThirdPpParams' => $translatedSelfIntroductionThirdPpParams,
10088            'translationModel' => $this->Translation,
10089            'hideLimitedPlanReservation' => $hideLimitedPlanReservation,
10090            'teacherCoinBeforeDiscount' => empty($teacherCoinBeforeDiscount)? 0: (int)$teacherCoinBeforeDiscount,
10091            'teacherCoinWithOp' => empty($teacherCoinWithOp)? 0: (int)$teacherCoinWithOp,
10092            'nativeOptionFlg' => $displayNativeOptionAmountFlg,
10093            'lessonCount' => $lessonCount,
10094        );
10095
10096        $this->set($setData);
10097        $this->set('avatar_teacher_detail', 1);
10098        if ($userId) {
10099            $points = $this->UsersPoint->find('first', array(
10100                'fields' => array('point'),
10101                    'conditions' => array(
10102                        'user_id' => $userId
10103                    )
10104                )
10105            );
10106
10107            $points = isset($points['UsersPoint']['point']) ? $points['UsersPoint']['point'] : 0;
10108            $reservePoint = Configure::read("reserve_point");
10109
10110            if (intval($reservePoint) < 1) $reservePoint = 0;
10111            //set promo discount for reservation
10112            // set paramater to 2 for reservation promo
10113            $bonus = CoinSetTable::getCoinSet(2);
10114            //check if the promo is valid today
10115            if ($bonus) {
10116                $reservePoint = $bonus;
10117            }
10118        } else {
10119            $points = 0;
10120        }
10121
10122        # get user timezone
10123        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
10124        $user_timezone_data = $this->Timezone->find('first',
10125            array(
10126                'fields' => array(
10127                    'Timezone.city_eng',
10128                    'Timezone.utc_offset',
10129                    'Timezone.country_code_id'
10130                ),
10131                'conditions' => array(
10132                    'Timezone.id' => $user_timezone_id
10133                ),
10134                'recursive' => -1
10135            )
10136        );
10137
10138        // - NJ-3653 get country
10139        $countryTimezone = null;
10140        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
10141            // - Get all country Code
10142            $countryOptions = $this->Timezone->countryOptions();
10143
10144            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
10145            $countryName = $countryOptions[$countryCodeId]['country_name'];
10146
10147            if (isset($countryName) && $countryName) {
10148                $countryTimezone = $countryName;
10149            }
10150        }
10151
10152
10153        $this->set('countryTimezone', $countryTimezone);
10154        $this->set('userTimezoneData', $user_timezone_data);
10155
10156        #user time
10157        $datetime = date('Y-m-d H:i:s');
10158        $localTime = $this->displayTime;
10159        // NJ-29496
10160        if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
10161            $formattedDate = date('d/m/Y G:i', $localTime);
10162        } else {
10163            $formattedDate = date('Y/m/d G:i', $localTime);
10164        }
10165    
10166        $this->set('userCurrentTime', $formattedDate);        
10167
10168        $this->set('points', $points);
10169        $this->set('reservePoint', isset($reservePoint)? $reservePoint: 0);
10170
10171        $countrids_no = Configure::read('sms_send.countrids_no');
10172        $this->set('countrids_no', $countrids_no);
10173
10174        $deviceNotSupported = false;
10175        $ua = (!empty(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']))) ? myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) : '';
10176        if (strpos($ua, 'Android') !== false || strpos($ua, 'iPhone') !== false || strpos($ua, 'iPad') !== false || strpos($ua, 'iPod') !== false) {
10177            $deviceNotSupported = true;
10178        }
10179        $this->set('deviceNotSupported', $deviceNotSupported);
10180
10181        $this->set('statusCheck', array(1, 4));
10182
10183        $this->set('login', $this->Auth->loggedIn());
10184
10185        //get preset textbook -> last viewed -> default textbook category first lesson
10186        $presetParams = array("user_id" => $this->Auth->User('id'));
10187
10188        //add additional parameters
10189        if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
10190            $presetParams["lang"] = $this->localizeDir;
10191        }
10192        //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
10193        $presetParams["userValidForSSBEDT"] = $this->userValidForSSBEDT();
10194
10195        #NC-9916
10196        if($data['User']) {
10197            $presetParams['native_language2'] = $userData->native_language2;
10198            $presetParams["userMembershipType"] = $userData->getMembershipTypeIndex();
10199        }
10200        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
10201
10202        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
10203            # for preset
10204            $presetParams['connect_id'] = $preset_data['preset_connect_id'];
10205            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
10206
10207        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
10208            # use last viewed textbook if no preset data.
10209            $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
10210            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
10211
10212        }
10213
10214        // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
10215        $presetParams['is_pc_flg'] = 1;
10216
10217        # fetch preset
10218        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
10219        if(!$preset) {
10220            unset($presetParams['connect_id']);
10221            unset($presetParams['last_opened_date']);
10222            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
10223        }
10224
10225        // NC-8020
10226        $this->set('textbookConnectId', $preset['textbook_connect_id']);
10227        $this->set('textbookCategoryTypeId', $preset['textbook_type']);
10228
10229        //set variable preset textbook to be displayed
10230        $this->set('preset', $preset);
10231        // apology list (cancellation of reservation)
10232         $apologyList = array(); // NC-4749 : hide list, used function from model and made it popup modal
10233        $this->set('apologyList', $apologyList);
10234
10235        $getAvatarParams = array(
10236            "avatar_id" => $teacherId,
10237            "user_id" => $this->Auth->user('id'),
10238            "stealth_flg" => $this->Cookie->read('stealth.setting')
10239        );
10240        $avatarTeacherIds = $this->Teacher->getAvatarTeacherId($getAvatarParams);
10241
10242        // NJ-18780 : check if user is normal lite plan
10243        $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
10244        $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
10245
10246
10247        $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
10248            'userId' => $this->Auth->user('id'),
10249            'teacherId' => $avatarTeacherIds,
10250            'timeDiff' => $this->timeDiff,
10251            'isNormalLitePlanUser' => $isNormalLitePlanUser
10252        ));
10253
10254        // dynamic techer
10255
10256        $avatarParams = array(
10257            "user_id" => $this->Auth->user('id'),
10258            "avatar_id" => $teacherId
10259        );
10260
10261        $avatarTeacherArr = $this->Avatar->availableTeacher($avatarParams);
10262        $lessTime = 0;
10263        if ( isset($avatarTeacherArr["teacher_id"]) ) {
10264            $avatarTeacherId = $avatarTeacherArr["teacher_id"];
10265        }
10266        if ( isset($avatarTeacherArr["less_time"]) ) {
10267            $lessTime = $avatarTeacherArr["less_time"];
10268        }
10269        $options['isAvatar'] = 1;
10270        $reviewsCount = $this->UsersClassEvaluation->getCommentCount($teacherId, $options);
10271
10272        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
10273        $this->set('reviewsCount', $reviewsCount);
10274        $this->set('teacherName', $teacherName);
10275        $this->set('teacherImageSrc', $teacherImageSrc);
10276        $this->set('lessTime', $lessTime);
10277        $this->set('isAvatar',true);
10278        $this->set('avatarTeacherId', $avatarTeacherId);
10279        $this->set('disabledSchedule', json_encode($disabledSchedule));
10280        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
10281        $this->set('noIndexFlgOveride', ($this->localizeDir != Configure::read('default.user_language') ? true : false));
10282
10283        // - NJ-6390 add highLightFlag
10284        $this->set('highLightFlag', isset($highLightFlag) && $highLightFlag? $highLightFlag: null);
10285
10286        // class evaluation
10287        if ($this->request->query('chatHash')) {
10288            $chatHash = $this->request->query('chatHash');
10289
10290            // Check if chatHash is valid
10291            $this->LessonOnairsLog->openDBReplica();
10292            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
10293            $this->LessonOnairsLog->closeDBReplica();
10294
10295            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
10296                $this->LessonOnair->openDBReplica();
10297                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
10298                $this->LessonOnair->closeDBReplica();
10299
10300                if(!$allData) {
10301                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
10302                }
10303            }
10304
10305            $userValidForSSBEDT = false;
10306            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
10307                $userValidForSSBEDT = true;
10308            }
10309            $param = array(
10310                "user_id" => $userId,
10311                "select_method" => "first",
10312                "env_flag" => "all",
10313                'connect_id' => $allData['Connect']['id'],
10314                "user_locale" => $this->localizeDir,
10315                "userValidForSSBEDT" => $userValidForSSBEDT
10316            );
10317            
10318            if ($userId && isset($allData['Connect']['category_id']) && $allData['Connect']['category_id']) {
10319                $corporateParams = array('user_id' => $userId);
10320                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
10321                
10322                if ($corporateTextbookControlFlg == 1) {
10323                    $categoryData = $this->TextbookCategory->getKidsCategoryTypesById($allData['Connect']['category_id']);
10324                    if (!empty($categoryData)) {
10325                        $param['include_kids_category'] = $allData['Connect']['category_id'];
10326                    }
10327                }
10328            }
10329            $textbookData = $this->Textbook->getTextbooks($param);
10330            $data = $textbookData['res_data'];
10331
10332            $isReservedLesson = 2;
10333            $hideTextbookChangeModal = $enableNextTextbookChapterButton = 'false';
10334            $latestPresetTextbookConnect_id = (int)$data['TextbookConnect']['id'];
10335            $latestPresetTextbookConnect_categoryId = (int)$data['TextbookConnect']['category_id'];
10336            $latestPresetTextbookConnect_subCategoryId = (int)$data['TextbookConnect']['subcategory_id'];
10337            $latestPresetTextbookCategory_textbookCatType = (int)$data['TextbookCategory']['textbook_category_type'];
10338
10339            //Optimize PC /lesson-finish page
10340            $lessonOnairLatestData = $this->LessonOnair->getLatestLessonOnairDetailsOfUserAndTeacher($userId, $teacherId);
10341            if(isset($lessonOnairLatestData) && $lessonOnairLatestData) {
10342                $lessonOnairLatestDataFlg = true;
10343                $lessonOnairLatest_connectId = (int)$lessonOnairLatestData['LessonOnair']['connect_id'];
10344                $lessonOnairLatest_lessonType = (int)$lessonOnairLatestData['LessonOnair']['lesson_type'];
10345            } else {
10346                $lessonOnairLogsLatestData = $this->LessonOnairsLog->getLatestLessonLogsDetailsOfUserAndTeacher($userId, $teacherId);
10347                if(isset($lessonOnairLogsLatestData) && $lessonOnairLogsLatestData) {
10348                    $lessonOnairLogsLatest_connectId = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['connect_id'];
10349                    $lessonOnairLogsLatest_lessonType = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['lesson_type'];
10350                }
10351            }
10352
10353            // - initialize empty variable
10354            $isLatestPresetTextbookMadeDuringLastLesson = [];
10355            $latestPresetTextbookParams = [];
10356
10357            // For hiding of textbookchange modal (if reserved lesson & not studySapuri)
10358            if ($lessonOnairLatestDataFlg) {
10359                $latestPresetTextbookParams = array (
10360                    'userId' => $userId,
10361                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
10362                    'lessonOnairLatest_startTime' => $lessonOnairLatestData['LessonOnair']['start_time'],
10363                    'lessonOnairLatest_endTime' => $lessonOnairLatestData['LessonOnair']['end_time']
10364                );
10365
10366            // - if has lesson onairs log
10367            } else if ($lessonOnairLogsLatestData) {
10368                $latestPresetTextbookParams = array (
10369                    'userId' => $userId,
10370                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
10371                    'lessonOnairLogsLatest_startTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['start_time'],
10372                    'lessonOnairLogsLatest_endTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['end_time']
10373                );
10374
10375            }
10376            
10377            // - if has parameters for fetching latest textbook parameters
10378            if ($latestPresetTextbookParams) {
10379                $isLatestPresetTextbookMadeDuringLastLesson = $this->UsersTextbookInfo->checkLatestUserTextbookInfoChangedDuringLesson($latestPresetTextbookParams);
10380            }
10381
10382            // -  check sapuri ID
10383            if(!isset($this->studySapuriId) || !$this->studySapuriId) {
10384                if (isset($lessonOnairLatestDataFlg)) {
10385                    if (is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
10386                        && $latestPresetTextbookConnect_id == $lessonOnairLatest_connectId && $lessonOnairLatest_lessonType == $isReservedLesson
10387                    ) {
10388                        $hideTextbookChangeModal = 'true';
10389                    }
10390                } else {
10391                    if (
10392                        is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
10393                        && $latestPresetTextbookConnect_id == $lessonOnairLogsLatest_connectId &&  $lessonOnairLogsLatest_lessonType == $isReservedLesson
10394                    ) {
10395                        $hideTextbookChangeModal = 'true';
10396                    }
10397                }
10398            }
10399
10400            $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
10401
10402            // For enabling next textbook chapter button (if not callan and not ongoing lesson)
10403            if (
10404                $hideTextbookChangeModal == 'false'
10405                && (isset($latestPresetTextbookCategory_textbookCatType) &&  !in_array($latestPresetTextbookCategory_textbookCatType, Configure::read('callan_textbook_type')))
10406                && (isset($onGoingLesson) && $onGoingLesson == false)
10407            ) {
10408                $allTextbookParams = array(
10409                    'category_id' => $latestPresetTextbookConnect_categoryId, 
10410                    'connect_id' => $latestPresetTextbookConnect_id,
10411                    'subcategory_id' => $latestPresetTextbookConnect_subCategoryId
10412                );
10413                
10414                $allTextbookChapters = $this->TextbookConnect->getTextbookPrevAndNextFunction($allTextbookParams);
10415                // if has next textbook chapter, show button 
10416                if (
10417                    is_array($allTextbookChapters) && !is_null($allTextbookChapters) 
10418                    && ($allTextbookChapters['next'] !== '' && !is_null($allTextbookChapters['next']))
10419                ) {
10420                    $enableNextTextbookChapterButton = 'true';
10421                }
10422            }
10423
10424            $this->set('enableNextTextbookChapterButton', $enableNextTextbookChapterButton);
10425
10426            if(!empty($this->sharedUserData['User'])){
10427                // - campaing stamps
10428                $this->getActiveCampaignStampData();
10429            }
10430
10431            $this->set('chatHash', $chatHash);
10432        }
10433
10434        //NJ-33414
10435        $this->UsersDetail->openDBReplica();
10436        $fetchUsersDetail = $this->UsersDetail->find('first', array(
10437            'fields' => array(
10438                'lesson_request_flg'
10439            ),
10440            'conditions' =>  array('user_id' => $this->sharedUserData['User']['id']),
10441            'recursive' => -1
10442        ));
10443        $this->UsersDetail->closeDBReplica();
10444
10445        $lessonRequestFlg = $fetchUsersDetail ? $fetchUsersDetail['UsersDetail']['lesson_request_flg'] : 1;
10446        $this->set('lessonRequestFlg',$lessonRequestFlg);
10447
10448        //-- NJ-44869 skip communication modal
10449        $lessonSystemTroubleFlg = 0;
10450        $hideConnectionModalFlg = 0;
10451
10452        // if (!empty($chatHash)) {
10453        //     $memcached = new myMemcached();
10454        //     $lessonSystemTroubleCache = $memcached->get('lesson_system_trouble_' . $chatHash);
10455        //     $lessonDisconnectionChatHash = $memcached->get('lesson_disconnection_flag_' . $teacherId);
10456            
10457        //     $hideConnectionModalFlg = $memcached->get('hide_connection_modal_flg_'.$teacherId.'-'.$chatHash);
10458
10459        //     if (!empty($lessonSystemTroubleCache)) {
10460        //         $memcached->delete('lesson_system_trouble_' . $chatHash);
10461        //         $lessonSystemTroubleFlg = 1;
10462        //     } elseif (!empty($lessonDisconnectionChatHash) && $lessonDisconnectionChatHash == $chatHash) {
10463        //         $lessonSystemTroubleFlg = 1;
10464        //     }
10465        // }
10466
10467        $this->set('lessonSystemTroubleCache', $lessonSystemTroubleFlg);
10468        $this->set('hideConnectionModalFlg', $hideConnectionModalFlg);
10469    }
10470
10471    /**
10472     * @api {get} /user/waiting/getTeacherReviews getTeacherReviews()
10473     * @apiName getTeacherReviews
10474     * @apiGroup Waiting
10475     * @apiDescription Retrieves the reviews for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the reviews data.
10476     *
10477     * @apiBody {String} [teacherId] The ID of the teacher.
10478     * @apiBody {Boolean} [isCounseling] Indicates whether the request is for a counseling teacher.
10479     * @apiBody {Boolean} [isAvatar] Indicates whether the request is for an avatar teacher.
10480     * @apiBody {Boolean} [isCustomerSupport] Indicates whether the request is for a customer support teacher.
10481     * @apiBody {Number} [order] The order of the reviews.
10482     * @apiBody {Number} [limit=4] The limit of reviews to retrieve.
10483     * @apiBody {Number} [page=1] The current page number.
10484     * @apiBody {Number} [rate] The rating filter for the reviews.
10485     * @apiBody {String} [textbook_course] The textbook course filter for the reviews.
10486     * @apiBody {String} [textbook_series] The textbook series filter for the reviews.
10487     * @apiBody {String} [textbook_preset] The textbook preset filter for the reviews.
10488     * @apiBody {String} [textbook_favorite] The textbook favorite filter for the reviews.
10489     * @apiBody {Boolean} [load_categories] Indicates whether to load the textbook categories.
10490     * @apiBody {Boolean} [load_paging] Indicates whether to load the paging data.
10491     * 
10492     * @apiSuccess {String} htmlReviews The HTML content for the reviews.
10493     * @apiSuccess {Number} counselorReviewsCount The count of counselor reviews.
10494     * @apiSuccess {String} htmlPaging The HTML content for the paging data.
10495     * @apiSuccess {Object[]} textbookCategories The textbook categories data.
10496     * @apiSuccess {String} textbookCategories.id The ID of the textbook category.
10497     * @apiSuccess {String} textbookCategories.name The name of the textbook category.
10498     * @apiSuccess {String} textbookCategories.image The image URL of the textbook category.
10499     *
10500     * @apiSuccessExample {json} Success-Response:
10501     *     {
10502     *         "htmlReviews": "<div>Reviews HTML</div>",
10503     *         "counselorReviewsCount": 10,
10504     *         "htmlPaging": "<div>Paging HTML</div>",
10505     *         "textbookCategories": [
10506     *             {
10507     *                 "id": "1",
10508     *                 "name": "Category Name",
10509     *                 "image": "http://example.com/image.jpg"
10510     *             },
10511     *             ...
10512     *         ]
10513     *     }
10514     *
10515     * @apiError {String} error Message indicating the error.
10516     *
10517     * @apiErrorExample {json} Error-Response:
10518     *     {
10519     *         "error": "Invalid request."
10520     *     }
10521     * 
10522     * @apiSampleRequest off
10523     */
10524    public function getTeacherReviews() {
10525        $this->autoRender = $this->layout = false;
10526        $get = $this->request->query;
10527
10528        if (isset($get['teacherId']) && !filter_var($get['teacherId'], FILTER_VALIDATE_INT)) {
10529            return json_encode([]);
10530        }
10531
10532        $counselorReviewsCount = 0;
10533        if (isset($get['teacherId']) || isset($get['isCounseling']) || isset($get['isAvatar']) || isset($get['isCustomerSupport'])) {
10534            if (isset($get['order'])) {
10535                $this->Cookie->write('teacherReviewOrder', $get['order'], true, 0);
10536            }
10537            $order = $this->Cookie->read('teacherReviewOrder') ?? 0;
10538            $limit = !empty($get['limit']) && is_numeric($get['limit']) ? (int) $get['limit'] : 4;
10539            $page  = !empty($get['page'])  && is_numeric($get['page'])  ? (int) $get['page']  : 1;
10540            $params = array(
10541                'order' => $order,
10542                'limit' => $limit,
10543                'offset' => ($page - 1) * $limit,
10544                'userId' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
10545                'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
10546                'lang' => $this->localizeDir
10547            );
10548
10549            // office teacher
10550            if ( isset($get['isCounseling']) || isset($get['isCustomerSupport']) ) {
10551                myTools::initializeApiTunnel(array('TeachersCounselorReviewsController'));
10552                $teachersReviews = new TeachersCounselorReviewsController();
10553                $teachersReviews->params = $params;
10554                $isCustomerSupport = isset($get['isCustomerSupport']) ? true : false;
10555                $reviews = $teachersReviews->getAllCounselEvaluation($isCustomerSupport);
10556                $counselorReviewsCount = $teachersReviews->getCountAllEvaluation($isCustomerSupport);
10557            } else {
10558                myTools::initializeApiTunnel(array('TeachersReviewsController'));
10559                $teachersReviews = new TeachersReviewsController();
10560                $params['conditions'] = array();
10561                if(isset($get['isAvatar'])) {
10562                    if(!isset($get['load_categories'])) {
10563                        $params['conditions'][] = "UsersClassEvaluation.teacher_id IN (SELECT id FROM teachers WHERE avatar_id = {$get['teacherId']} AND status = 1)";
10564                        $params['conditions'][] = "UsersClassEvaluation.approve_flag = 1";
10565                        $params['conditions'][] = "UsersClassEvaluation.user_comment <> ''";
10566                    }
10567                    $params['isAvatar'] = true;
10568                    $params['avatarTeacherId'] = $get['teacherId'];
10569                } else {
10570                    $params['conditions']['UsersClassEvaluation.teacher_id'] = $get['teacherId'];
10571                }
10572
10573                $params['rate'] = $get['rate'] ?? null;
10574                $params['textbook_course'] = $get['textbook_course'] ?? null;
10575                $params['textbook_series'] = $get['textbook_series'] ?? null;
10576                $params['textbook_preset'] = $get['textbook_preset'] ?? null;
10577                $params['textbook_favorite'] = $get['textbook_favorite'] ?? null;
10578                $params['is_sapuri_user'] = $this->isStudySapuriUser ? true : false;
10579
10580
10581                $userTable = new UserTable($this->Auth->user());
10582                $sapuriPlan = $userTable->isStudySapuri();
10583                $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
10584                if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
10585                    $params['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
10586                } else {
10587                    $params['textbook_category_type_not_in'] = $sapuriTextbookType;
10588                }
10589
10590                if ($userId = $this->Auth->user('id')) {
10591                    $corporateParams = array('user_id' => $userId);
10592                    $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
10593                    
10594                    if ($corporateTextbookControlFlg == 1) {
10595                        $params['textbook_category_type_not_in'] = Configure::read('kids_callan_kids_textbook_category_types');
10596                    }
10597                }
10598
10599                $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir, true);
10600                $params['build_conditions']['language_id'] = $reviewLanguage[0];
10601                $params['build_conditions']['not_language_ids'] = $reviewLanguage[1] ?? null;
10602                
10603                $teachersReviews->params = $params;
10604                $reviews = $teachersReviews->getReviews();
10605
10606                if (isset($get['load_categories'])) {
10607                    $teachersReviews->params['load_favorite'] = true;
10608                    $teachersReviews->params['isLoadCategories'] = true;
10609                    $textbookCategories = $teachersReviews->getReviewTextbooks($this->sharedUserData['User'], $this->localizeDir);
10610                }
10611            }
10612            if ($reviews) {
10613                $view = new View($this, false);
10614                $htmlReviews = $view->element('teacherReviews', array('reviews' => $reviews));
10615
10616                if (isset($get['load_paging'])) {
10617                    $commentCount = $this->UsersClassEvaluation->useReplica()->countTeacherReviews($teachersReviews->convertOldParams($params), true);
10618                    $paging = myTools::paging($page, $commentCount, $limit);
10619                    $htmlPaging = $view->element('pager_link_instructor_reviews_ng', ['paging' => $paging, 'order' => $order]);
10620                }
10621            }
10622        }
10623
10624        $returnArr = array();
10625        if (isset($htmlReviews)) {
10626            $returnArr['htmlReviews'] = $htmlReviews;
10627            $returnArr['counselorReviewsCount'] = $counselorReviewsCount;
10628        }
10629        if (isset($htmlPaging)) {
10630            $returnArr['htmlPaging'] = $htmlPaging;
10631        }
10632        if(isset($textbookCategories)) {
10633            $returnArr['textbookCategories'] = $textbookCategories;
10634        }
10635
10636        return json_encode($returnArr);
10637    }
10638
10639    /**
10640     * @api {post} /user/waiting/favoriteTextbookCategoryForReview favoriteTextbookCategoryForReview()
10641     * @apiName favoriteTextbookCategoryForReview
10642     * @apiGroup Waiting
10643     * @apiDescription Retrieves the favorite textbook categories for review for the authenticated user in Native Camp. It returns the favorite textbook categories data.
10644     *
10645     * @apiBody {String} [lang=ja] The language code for the request.
10646     * @apiBody {Boolean} [isAvatar] Indicates whether the request is for an avatar teacher.
10647     * @apiBody {String} [teacherId] The ID of the teacher.
10648     * 
10649     * @apiSuccess {Object[]} favorite The favorite textbook categories data.
10650     * @apiSuccess {String} favorite.id The ID of the textbook category.
10651     * @apiSuccess {String} favorite.name The name of the textbook category.
10652     * @apiSuccess {String} favorite.image The image URL of the textbook category.
10653     *
10654     * @apiSuccessExample {json} Success-Response:
10655     *     {
10656     *         "favorite": [
10657     *             {
10658     *                 "id": "1",
10659     *                 "name": "Category Name",
10660     *                 "image": "http://example.com/image.jpg"
10661     *             },
10662     *             ...
10663     *         ]
10664     *     }
10665     *
10666     * @apiError {String} error Message indicating the error.
10667     *
10668     * @apiErrorExample {json} Error-Response:
10669     *     {
10670     *         "error": "Invalid request."
10671     *     }
10672     * 
10673     * @apiSampleRequest off
10674     */
10675    public function favoriteTextbookCategoryForReview() {
10676        $this->autoRender = false;
10677        $result = [];
10678        if (isset($this->request->data) ) {
10679            $inputs = $this->request->data;
10680            $lang = 'ja';
10681            if (isset($inputs['lang']) && !empty($inputs['lang'])) $lang = $inputs['lang'];
10682            $this->localizeDir = $lang;
10683
10684            myTools::initializeApiTunnel(array('TeachersReviewsController'));
10685            $teachersReviews = new TeachersReviewsController();
10686            $params = array(
10687                'userId' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
10688                'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
10689                'lang' => $this->localizeDir
10690            );
10691            $params['conditions'] = array();
10692
10693            if( isset($inputs['isAvatar']) && $inputs['isAvatar'] ) {
10694                $params['isAvatar'] = true;
10695                $params['isLoadCategories'] = true;
10696            } else {
10697                $params['conditions']['UsersClassEvaluation.approve_flag'] = 1;
10698                $params['conditions']['UsersClassEvaluation.user_comment <>'] = '';
10699                $params['conditions']['UsersClassEvaluation.teacher_id'] = $inputs['teacherId'];
10700            }
10701            $params['is_sapuri_user'] = $this->isStudySapuriUser ? true : false;
10702
10703            $userTable = new UserTable($this->Auth->user());
10704            $sapuriPlan = $userTable->isStudySapuri();
10705            $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
10706
10707            if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
10708                $params['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
10709            } else {
10710                $params['textbook_category_type_not_in'] = $sapuriTextbookType;
10711            }
10712
10713            if ($userId = $this->Auth->user('id')) {
10714                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl(['user_id' => $userId]);
10715                if ($corporateTextbookControlFlg == 1) {
10716                    $params['textbook_category_type_not_in'] = Configure::read('kids_callan_kids_textbook_category_types');
10717                }
10718            }
10719
10720            $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir, true);
10721            $params['build_conditions']['language_id'] = $reviewLanguage[0] ?? null;
10722            $params['build_conditions']['not_language_ids'] = $reviewLanguage[1] ?? null;
10723            $params['load_favorite'] = true;
10724            $teachersReviews->params = $params;
10725
10726            $textbookCategories = $teachersReviews->getReviewTextbooks($this->sharedUserData['User'], $this->localizeDir);
10727            $result = !empty($textbookCategories) && isset($textbookCategories['favorite']) ? $textbookCategories['favorite'] : [];
10728        }
10729        return json_encode($result);
10730    }
10731
10732    /**
10733     * @api {post} /user/waiting/teacherAvatarStatus teacherAvatarStatus()
10734     * @apiName teacherAvatarStatus
10735     * @apiGroup Waiting
10736     * @apiDescription Retrieves the status of avatar teachers for the authenticated user in Native Camp. It checks the availability of the specified avatar teachers and returns their status.
10737     *
10738     * @apiBody {String[]} avatar_id_array The array of avatar teacher IDs.
10739     * 
10740     * @apiSuccess {Object} result The status of the avatar teachers.
10741     * @apiSuccess {Object} result.avatarId The status data for the avatar teacher.
10742     * @apiSuccess {Boolean} result.avatarId.available Indicates whether the avatar teacher is available.
10743     * @apiSuccess {String} result.avatarId.status The status of the avatar teacher.
10744     *
10745     * @apiSuccessExample {json} Success-Response:
10746     *     {
10747     *         "123": {
10748     *             "available": true,
10749     *             "status": "online"
10750     *         },
10751     *         "456": {
10752     *             "available": false,
10753     *             "status": "offline"
10754     *         }
10755     *     }
10756     *
10757     * @apiError {String} error Message indicating the error.
10758     *
10759     * @apiErrorExample {json} Error-Response:
10760     *     {
10761     *         "error": "Invalid request."
10762     *     }
10763     * 
10764     * @apiSampleRequest off
10765     */
10766    public function teacherAvatarStatus() {
10767        $this->autoRender = $this->layout = false;
10768        $userId = $this->Auth->user('id') ? $this->Auth->user('id') : '';
10769        $post = $this->request->data;
10770        $avatarIdArr = array_flip(Configure::read("default_avatar_detail"));
10771        $result = array();
10772
10773        if(isset($post["avatar_id_array"]) && is_array($post["avatar_id_array"]) ) {
10774            foreach ($post["avatar_id_array"] as $key => $avatarId) {
10775
10776                    $params = array(
10777                        "user_id" => $userId,
10778                        "avatar_id" => $avatarId
10779                    );
10780                    $data = $this->Avatar->availableTeacher($params);
10781                    $result[$avatarId] = $data;
10782
10783
10784            }
10785
10786        }
10787
10788        return json_encode($result);
10789
10790    }
10791
10792    /**
10793     * @api {get} /user/waiting/checkMaintenanceForAlert checkMaintenanceForAlert()
10794     * @apiName checkMaintenanceForAlert
10795     * @apiGroup Waiting
10796     * @apiDescription Checks if there is an upcoming maintenance period and returns an alert message if maintenance is scheduled.
10797     *
10798     * @apiSuccess {Number} is_maintenance Indicates whether maintenance is scheduled (0: No, 1: Yes).
10799     * @apiSuccess {String} message The maintenance alert message.
10800     * @apiSuccess {Number} [timezone_id] The ID of the user's timezone (if applicable).
10801     *
10802     * @apiSuccessExample {json} Success-Response:
10803     *     {
10804     *         "is_maintenance": 1,
10805     *         "message": "2:00AMより定期メンテナンスを行います。レッスンは、2:00AMに終了しますのでご了承ください。",
10806     *         "timezone_id": 1
10807     *     }
10808     *
10809     * @apiError {String} error Message indicating the error.
10810     *
10811     * @apiErrorExample {json} Error-Response:
10812     *     {
10813     *         "error": "Invalid request."
10814     *     }
10815     * 
10816     * @apiSampleRequest off
10817     */
10818    public function checkMaintenanceForAlert() {
10819        $this->autoRender = $this->layout = false;
10820        $response = array(
10821            'is_maintenance' => 0,
10822            'message' => __d('waiting','2:00AMより定期メンテナンスを行います。レッスンは、2:00AMに終了しますのでご了承ください。')
10823        );
10824        if (!myTools::checkCompanyIP($_SERVER['REMOTE_ADDR'])) {
10825            $conditions = array(
10826                'is_active' => 1,
10827                'start_date <= DATE_ADD(NOW(), INTERVAL 26 MINUTE)',
10828                'end_date >= NOW()'
10829            );
10830            $maintenanceModel = ClassRegistry::init('Maintenance');
10831            $maintenanceModel->openDBReplica();
10832            $maintenance = $maintenanceModel->find('first',array(
10833                'conditions' => $conditions
10834            ));
10835            $maintenanceModel->closeDBReplica();
10836            if ($maintenance) {
10837                $response['is_maintenance'] = 1;
10838                # maintenance time on user side
10839                if ($this->sharedUserData['User']['timezone_id']) {
10840                    $response['timezone_id'] = $this->sharedUserData['User']['timezone_id'];
10841                    $timezones = $this->Timezone->getFormattedRecruitTimezones();
10842                    $userTimeZoneData = $timezones[$this->sharedUserData['User']['timezone_id']];
10843                    $datetime = date($maintenance['Maintenance']['start_date']); // maintenance time
10844                    $timestamp = strtotime($datetime);
10845                    $fromTime = $timestamp + (($userTimeZoneData['jp_time_diff'] / 60) * 60 * 60);
10846                    $userMaintenanceTime = date("g:iA", $fromTime);
10847                    $uData = $this->Timezone->getTimezoneUserData($this->sharedUserData['User']['timezone_id']);
10848                    $alertMessageTime = $userMaintenanceTime. " (UTC".$uData['Timezone']['utc_offset'].") " .$userTimeZoneData['data-timezone_name'];
10849                    $alertMessage = sprintf(__d('waiting','%s より定期メンテナンスを行います。時間になりましたらレッスンも終了しますのでご了承ください。'), $alertMessageTime);
10850                    $response['message'] = $alertMessage;
10851                }
10852            }
10853        }
10854        echo json_encode($response);
10855    }
10856
10857    private function isAvatar($teacherID=null){
10858        $result = null;
10859        if ($teacherID) {
10860            $get = $this->Teacher->useReplica()->find('first',array(
10861                    'conditions' => array( 'Teacher.id' => $teacherID ),
10862                    'fields' => array(
10863                        'Teacher.id',
10864                        'Teacher.avatar_id',
10865                        'Teacher.avatar_parent_flg',
10866                        'Teacher.avatar_flg'
10867                    ),
10868                    'recursive' => -1
10869                )
10870            );
10871            if ($get) {
10872                // check parent
10873                $avatarParent = isset($get['Teacher']['avatar_parent_flg']) && $get['Teacher']['avatar_parent_flg'] ? $get['Teacher']['avatar_parent_flg'] : 0;
10874                $avatar = isset($get['Teacher']['avatar_flg']) && $get['Teacher']['avatar_flg'] ? $get['Teacher']['avatar_flg'] : 0;
10875                $avatarId = isset($get['Teacher']['avatar_id']) && $get['Teacher']['avatar_id'] ? $get['Teacher']['avatar_id'] : 0;
10876
10877                if ( ( $avatar && $avatarId ) || $avatarParent ) {
10878                    if ( $avatar && $avatarId ) {
10879                        $result = $avatarId;
10880                    }
10881                    if ($avatarParent) {
10882                        $result = $teacherID;
10883                    }
10884                }
10885            }
10886        }
10887        return $result;
10888    }
10889
10890
10891
10892    //Retrieves the latest lesson history for a specific user with counselor teachers in Native Camp. It returns the lesson history data.
10893    public function counselorLatestLessonHistory($userId){
10894
10895        $memcache = new myMemcached();
10896        $textbookNamesCachedArr = $memcache->get(Configure::read('textbook_names_cache_key'));
10897
10898        $counselorTeacherId =  Configure::read('default_counselor_detail');
10899        //NC-7984
10900        $lessonHistoryJoins = array(
10901            "use index (user_id)",
10902            array(
10903                'type' => 'LEFT',
10904                'table' => 'users_class_evaluations',
10905                'alias' => 'usersClassEvaluations',
10906                'conditions' => array('usersClassEvaluations.chat_hash = LessonOnairsLog.chat_hash')
10907            ),
10908            array(
10909                'type' => 'LEFT',
10910                'table' => 'textbook_connects',
10911                'alias' => 'TextbookConnect',
10912                'conditions' => 'LessonOnairsLog.connect_id = TextbookConnect.id'
10913            ),
10914            array(
10915                'type' => 'LEFT',
10916                'table' => 'textbook_categories',
10917                'alias' => 'TextbookCategory',
10918                'conditions' => 'TextbookConnect.category_id = TextbookCategory.id'
10919            ),
10920            array(
10921                'type' => 'LEFT',
10922                'table' => 'textbook_subcategories',
10923                'alias' => 'TextbookSubategory',
10924                'conditions' => 'TextbookConnect.subcategory_id = TextbookSubategory.id'
10925            ),
10926            array(
10927                'type' => 'LEFT',
10928                'table' => 'textbooks',
10929                'alias' => 'Textbook',
10930                'conditions' => 'Textbook.id = TextbookConnect.textbook_id'
10931            ),
10932            array(
10933                'type' => 'LEFT',
10934                'table' => 'teachers',
10935                'alias' => 'Teacher',
10936                'conditions' => 'LessonOnairsLog.teacher_id = Teacher.id'
10937            ),
10938            array(
10939                'type' => 'LEFT',
10940                'table' => 'lesson_track_logs',
10941                'alias' => 'LessonTrackLogs',
10942                'conditions' => 'LessonTrackLogs.chat_hash = LessonOnairsLog.chat_hash'
10943            )
10944        );
10945        $lessonHistoryFields = array(
10946            'LessonOnairsLog.id',
10947            'LessonOnairsLog.start_time',
10948            'LessonOnairsLog.end_time',
10949            'LessonOnairsLog.created', //Lesson Data / time
10950            'LessonOnairsLog.chat_hash',
10951            'LessonOnairsLog.lesson_memo',
10952            'LessonOnairsLog.lesson_memo_disp_flg',
10953            'LessonOnairsLog.connect_id',
10954            'LessonOnairsLog.display_message',
10955            'LessonOnairsLog.teacher_id',
10956            'TextbookConnect.id',
10957            'usersClassEvaluations.rate', //Lesson rate
10958            'TextbookCategory.name',
10959            'TextbookCategory.type_id',
10960            'TextbookSubategory.name',
10961            'Textbook.name',
10962            'Teacher.id',
10963            'LessonTrackLogs.lesson_number'
10964        );
10965        $this->Teacher->openDBReplica();
10966        $subQuery = $this->Teacher->find(
10967            'list',
10968            array(
10969                'fields'     => array('Teacher.id'),
10970                'table'      => 'teachers',
10971                'alias'      => 'Teacher',
10972                'conditions' => array(
10973                    'Teacher.counseling_flg' => 1,
10974                    'Teacher.status' => 1
10975                ),
10976                'recursive' => -1
10977            )
10978        );
10979        $this->Teacher->closeDBReplica();
10980
10981        $lessonHistoryConditions = array(
10982            'LessonOnairsLog.teacher_id IN' => $subQuery,
10983            'LessonOnairsLog.user_id' => $userId,
10984            'LessonOnairsLog.delete_flg <> ' => $this->LessonOnairsLog::DELETED
10985        );
10986
10987        // - has localized directory
10988        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
10989            // - get the user's language id
10990            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
10991            if ($langId) {
10992
10993                $lessonHistoryJoins[] = array(
10994                    'type' => 'LEFT',
10995                    'table' => 'global_textbook_categories',
10996                    'alias' => 'GlobalTextbookCategory',
10997                    'conditions' => array(
10998                        'GlobalTextbookCategory.language_id' => $langId,
10999                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
11000                    )
11001                );
11002
11003                $lessonHistoryJoins[] = array(
11004                    'type' => 'LEFT',
11005                    'table' => 'global_textbook_subcategories',
11006                    'alias' => 'GlobalTextbookSubcategory',
11007                    'conditions' => array(
11008                        'GlobalTextbookSubcategory.language_id' => $langId,
11009                        'GlobalTextbookSubcategory.textbook_subcategory_id = TextbookSubategory.id'
11010                    )
11011                );
11012                $lessonHistoryJoins[] = array(
11013                    'type' => 'LEFT',
11014                    'table' => 'global_textbooks',
11015                    'alias' => 'GlobalTextbook',
11016                    'conditions' => array(
11017                        'GlobalTextbook.language_id' => $langId,
11018                        'GlobalTextbook.textbook_id = Textbook.id'
11019                    )
11020                );
11021                $this->LessonOnairsLog->virtualFields = array(
11022                    'gl_subcateg_name' => 'GlobalTextbookSubcategory.gl_name',
11023                    'gl_name' => 'GlobalTextbook.gl_name'
11024                );
11025                $lessonHistoryFields[] = 'gl_categ_name';
11026                $lessonHistoryFields[] = 'gl_subcateg_name';
11027                $lessonHistoryFields[] = 'gl_name';
11028            }
11029        }
11030
11031        // - get lesson history
11032        $this->LessonOnairsLog->openDBReplica();
11033        $latestLessonHistory = $this->LessonOnairsLog->find(
11034            'all',
11035            array(
11036                'joins' => $lessonHistoryJoins,
11037                'fields' => $lessonHistoryFields,
11038                'conditions' => $lessonHistoryConditions,
11039                'limit' => 10, //int
11040                'order' => 'LessonOnairsLog.start_time DESC'
11041            )
11042        );
11043        $this->LessonOnairsLog->closeDBReplica();
11044
11045        $this->set('lessonHistory', $latestLessonHistory);
11046        $this->set('textbookNamesCachedArr', $textbookNamesCachedArr);
11047        //NC-7984
11048    }
11049
11050
11051    //Retrieves the latest lesson history for a specific avatar teacher and user in Native Camp. It returns the lesson history data.
11052    public function avatarLatestLessonHistory($userId, $teacherId){
11053        $memcache = new myMemcached();
11054        $textbookNamesCachedArr = $memcache->get(Configure::read('textbook_names_cache_key'));
11055        //NC-7984
11056        $lessonHistoryJoins = array(
11057            "use index (user_id)",
11058            array(
11059                'type' => 'LEFT',
11060                'table' => 'users_class_evaluations',
11061                'alias' => 'usersClassEvaluations',
11062                'conditions' => array('usersClassEvaluations.chat_hash = LessonOnairsLog.chat_hash')
11063            ),
11064            array (
11065                'type' => 'LEFT',
11066                'table' => 'textbook_connects',
11067                'alias' => 'TextbookConnect',
11068                'conditions' => 'LessonOnairsLog.connect_id = TextbookConnect.id'
11069            ),
11070            array(
11071                'type' => 'LEFT',
11072                'table' => 'textbook_categories',
11073                'alias' => 'TextbookCategory',
11074                'conditions' => 'TextbookConnect.category_id = TextbookCategory.id'
11075            ),
11076            array(
11077                'type' => 'LEFT',
11078                'table' => 'textbook_subcategories',
11079                'alias' => 'TextbookSubategory',
11080                'conditions' => 'TextbookConnect.subcategory_id = TextbookSubategory.id'
11081            ),
11082            array(
11083                'type' => 'LEFT',
11084                'table' => 'textbooks',
11085                'alias' => 'Textbook',
11086                'conditions' => 'Textbook.id = TextbookConnect.textbook_id'
11087            ),
11088            array(
11089                'type' => 'LEFT',
11090                'table' => 'teachers',
11091                'alias' => 'Teacher',
11092                'conditions' => 'LessonOnairsLog.teacher_id = Teacher.id'
11093            ),
11094            array(
11095                'type' => 'LEFT',
11096                'table' => 'lesson_track_logs',
11097                'alias' => 'LessonTrackLogs',
11098                'conditions' => 'LessonTrackLogs.chat_hash = LessonOnairsLog.chat_hash'
11099            )
11100        );
11101        $lessonHistoryFields = array(
11102            'LessonOnairsLog.id',
11103            'LessonOnairsLog.start_time',
11104            'LessonOnairsLog.end_time',
11105            'LessonOnairsLog.created', //Lesson Data / time
11106            'LessonOnairsLog.chat_hash',
11107            'LessonOnairsLog.lesson_memo',
11108            'LessonOnairsLog.lesson_memo_disp_flg',
11109            'LessonOnairsLog.connect_id',
11110            'LessonOnairsLog.display_message',
11111            'TextbookConnect.id',
11112            'usersClassEvaluations.rate', //Lesson rate
11113            'TextbookCategory.name',
11114            'TextbookCategory.type_id',
11115            'TextbookSubategory.name',
11116            'Textbook.name',
11117            'Teacher.id',
11118            'LessonTrackLogs.lesson_number'
11119        );
11120        $this->Teacher->openDBReplica();
11121        $subQuery = $this->Teacher->find(
11122            'list',
11123            array(
11124                'fields'     => array('Teacher.id'),
11125                'table'      => 'teachers',
11126                'alias'      => 'Teacher',
11127                'conditions' => array(
11128                    "(Teacher.avatar_flg = 1 AND Teacher.counseling_flg = 0 AND Teacher.status = 1 AND Teacher.avatar_id = {$teacherId}) || (Teacher.avatar_parent_flg = 1 AND Teacher.id = {$teacherId})"
11129                ),
11130                'recursive' => -1
11131            )
11132        );
11133        $this->Teacher->closeDBReplica();
11134
11135        $lessonHistoryConditions = array(
11136            'LessonOnairsLog.user_id' => $userId,
11137            'LessonOnairsLog.delete_flg <> ' => $this->LessonOnairsLog::DELETED
11138        );
11139
11140        if(is_array($subQuery) && !empty($subQuery)){
11141            $lessonHistoryConditions['LessonOnairsLog.teacher_id IN'] = $subQuery;
11142        }
11143
11144        // - has localized directory
11145        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
11146            // - get the user's language id
11147            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
11148            if ($langId) {
11149
11150                $lessonHistoryJoins[] = array(
11151                    'type' => 'LEFT',
11152                    'table' => 'global_textbook_categories',
11153                    'alias' => 'GlobalTextbookCategory',
11154                    'conditions' => array(
11155                        'GlobalTextbookCategory.language_id' => $langId,
11156                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
11157                    )
11158                );
11159
11160                $lessonHistoryJoins[] = array(
11161                    'type' => 'LEFT',
11162                    'table' => 'global_textbook_subcategories',
11163                    'alias' => 'GlobalTextbookSubcategory',
11164                    'conditions' => array(
11165                        'GlobalTextbookSubcategory.language_id' => $langId,
11166                        'GlobalTextbookSubcategory.textbook_subcategory_id = TextbookSubategory.id'
11167                    )
11168                );
11169                $lessonHistoryJoins[] = array(
11170                    'type' => 'LEFT',
11171                    'table' => 'global_textbooks',
11172                    'alias' => 'GlobalTextbook',
11173                    'conditions' => array(
11174                        'GlobalTextbook.language_id' => $langId,
11175                        'GlobalTextbook.textbook_id = Textbook.id'
11176                    )
11177                );
11178
11179                $lessonHistoryFields[] = 'GlobalTextbookCategory.gl_name';
11180                $lessonHistoryFields[] = 'GlobalTextbookSubcategory.gl_name';
11181                $lessonHistoryFields[] = 'GlobalTextbook.gl_name';
11182            }
11183        }
11184
11185        // - get lesson history
11186        $this->LessonOnairsLog->openDBReplica();
11187        $latestLessonHistory = $this->LessonOnairsLog->find(
11188            'all',
11189            array(
11190                'joins' => $lessonHistoryJoins,
11191                'fields' => $lessonHistoryFields,
11192                'conditions' => $lessonHistoryConditions,
11193                'limit' => 10, //int
11194                'order' => 'LessonOnairsLog.start_time DESC'
11195            )
11196        );
11197        $this->LessonOnairsLog->closeDBReplica();
11198
11199        $this->set('lessonHistory', $latestLessonHistory);
11200        $this->set('textbookNamesCachedArr', $textbookNamesCachedArr);
11201        //NC-7984
11202    }
11203
11204    private function userAvailPopularTeacher($params=array()){
11205        $result = false;
11206        if ( isset($params['user_id']) && isset($params['avatar_id']) ) {
11207            $userId = $params['user_id'];
11208            $avatarId = $params['avatar_id'];
11209
11210            $getTeacherAvatars = $this->Teacher->getAvatarTeacherId($params);
11211            if ($getTeacherAvatars) {
11212                $disconCancel = Configure::read('accounting.disconnection_cancellation_lesson_finish');
11213                // - check if has db replica
11214                $this->LessonOnairsLog->openDBReplica();
11215                $countLessons = $this->LessonOnairsLog->find('count', array(
11216                        'conditions' => array(
11217                        'LessonOnairsLog.user_id' => $userId,
11218                        'LessonOnairsLog.teacher_id' => array_values($getTeacherAvatars),
11219                        'LessonOnairsLog.start_time IS NOT NULL',
11220                        'LessonOnairsLog.end_time IS NOT NULL',
11221                        'LessonOnairsLog.connect_id IS NOT NULL',
11222                        'LessonOnairsLog.lesson_finish' => 1
11223                    ),
11224                    'recursive' => -1
11225                ));
11226                $this->LessonOnairsLog->closeDBReplica();
11227
11228                if ($countLessons < 1) {
11229                    $result = true;
11230                }
11231
11232            }
11233
11234        }
11235        return $result;
11236    }
11237
11238
11239    //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
11240    private function userValidForSSBEDT(){
11241        $userValidForSSBEDT = false;
11242        if (
11243              (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) &&
11244              ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
11245        ){
11246            $userValidForSSBEDT = true;
11247        }
11248
11249        return $userValidForSSBEDT;
11250    }
11251
11252    /**
11253     * @api {post} /user/waiting/loadLiveLessonTeacher loadLiveLessonTeacher()
11254     * @apiName loadLiveLessonTeacher
11255     * @apiGroup Waiting
11256     * @apiDescription Retrieves the list of teachers available for live lessons in Native Camp. It checks if the request is an AJAX request and returns the list of live lesson teachers.
11257     *
11258     * @apiBody {Number} [current_page=1] The current page number.
11259     * @apiBody {Number} [limit] The limit of teachers to retrieve.
11260     * @apiBody {String} [local_timezone] The local timezone of the user.
11261     * @apiBody {Boolean} [isGuestViwer] Indicates whether the user is a guest viewer.
11262     * @apiBody {Boolean} [isMobile] Indicates whether the request is from a mobile device.
11263     * @apiBody {String} [template] The template to use for rendering the teacher list.
11264     * @apiBody {String} [token] The API token of the user.
11265     * 
11266     * @apiSuccess {Object[]} liveTeacherList The list of teachers available for live lessons.
11267     * @apiSuccess {String} liveTeacherList.name The teacher's name.
11268     * @apiSuccess {String} liveTeacherList.id The teacher's unique identifier.
11269     * @apiSuccess {String} liveTeacherList.profilePicture URL to the teacher's profile picture.
11270     * @apiSuccess {Boolean} ajaxDisplay Indicates if the request was made via AJAX.
11271     * @apiSuccess {Number} userJpTimeDiffSecond The time difference in seconds between the user's local time and Japan time.
11272     * @apiSuccess {Number} studentLessonPriorityTimeDelayInSeconds The delay in seconds for student lesson priority.
11273     * @apiSuccess {Object} teacherListLiveParameters The parameters for the live teacher list (if applicable).
11274     * @apiSuccess {String} teacherListLiveParameters.user_id The ID of the user.
11275     * @apiSuccess {String} teacherListLiveParameters.user_language The language of the user.
11276     * @apiSuccess {Boolean} teacherListLiveParameters.pc_view Indicates if the view is for PC.
11277     * @apiSuccess {Number} teacherListLiveParameters.page The current page number.
11278     * @apiSuccess {String} teacherListLiveParameters.template The template used for rendering the teacher list.
11279     * @apiSuccess {Boolean} teacherListLiveParameters.mobapp_view Indicates if the view is for mobile app.
11280     * @apiSuccess {Number} teacherListLiveParameters.limit The limit of teachers to retrieve.
11281     * @apiSuccess {Boolean} teacherListLiveParameters.isGuestViwer Indicates if the user is a guest viewer.
11282     * @apiSuccess {Boolean} teacherListLiveParameters.isMobile Indicates if the request is from a mobile device.
11283     *
11284     * @apiSuccessExample {json} Success-Response:
11285     *     {
11286     *         "liveTeacherList": [
11287     *             {
11288     *                 "name": "Teacher Name",
11289     *                 "id": "123456",
11290     *                 "profilePicture": "https://www.nativecamp.net/img/teacher/123456.jpg"
11291     *             },
11292     *             ...
11293     *         ],
11294     *         "ajaxDisplay": true,
11295     *         "userJpTimeDiffSecond": 32400,
11296     *         "studentLessonPriorityTimeDelayInSeconds": 60,
11297     *         "teacherListLiveParameters": {
11298     *             "user_id": "789",
11299     *             "user_language": "en",
11300     *             "pc_view": true,
11301     *             "page": 1,
11302     *             "template": "pc_usage",
11303     *             "mobapp_view": false,
11304     *             "limit": 10,
11305     *             "isGuestViwer": false,
11306     *             "isMobile": false
11307     *         }
11308     *     }
11309     *
11310     * @apiError {String} error Message indicating the error.
11311     *
11312     * @apiErrorExample {json} Error-Response:
11313     *     {
11314     *         "error": "Invalid request."
11315     *     }
11316     * 
11317     * @apiSampleRequest off
11318     */
11319    public function loadLiveLessonTeacher(){
11320        $data = $this->request->data;
11321        $liveTeacherList = array();
11322        $params = array();
11323        $currentPage = !empty($data['current_page']) ? $data['current_page'] : 1 ;
11324        $limit = isset($data['limit']) ? $data['limit'] : null;
11325        $userJpTimeDiffSecond = !empty($this->timeDiffSecond) ? $this->timeDiffSecond : 0;
11326        $isGuestViwer = !empty($data['isGuestViwer']) ? 1 : 0;
11327
11328        //- if token set
11329        if (!empty($this->request->query['token'])) {
11330            $this->User->openDBReplica();
11331            $this->sharedUserData = $this->User->find('first', [
11332                'conditions' => ['api_token' => $this->request->query['token']],
11333                'recursive' => -1
11334            ]);
11335            $this->User->closeDBReplica();
11336
11337        }
11338
11339        //-- get JP time difference for logout users
11340        if (
11341            (empty($this->sharedUserData['User']) || $isGuestViwer)
11342            && !empty($data['local_timezone'])
11343            && $data['local_timezone'] != 'Asia/Tokyo'
11344        ) {
11345            $localTimezoneName = explode('/', $data['local_timezone']);
11346            if ( !empty($localTimezoneName[1]) ) {
11347                $this->Timezone->openDBReplica();
11348                $jpTimeDiff = $this->Timezone->find('first', array(
11349                    'fields' => 'jp_time_diff',
11350                    'conditions' => array(
11351                        'Timezone.city_eng LIKE ? ' => array($localTimezoneName[1])
11352                    ),
11353                    'recursive' => -1
11354                ));
11355                $this->Timezone->closeDBReplica();
11356                $userJpTimeDiffSecond = !empty($jpTimeDiff['Timezone']['jp_time_diff']) ? ((int)$jpTimeDiff['Timezone']['jp_time_diff'] * 60) : $userJpTimeDiffSecond;
11357            }
11358        }
11359
11360        //-- check if current user can use live lesson
11361        if ( 
11362            $isGuestViwer
11363            || empty($this->sharedUserData['User']) 
11364            || UserTable::canJoinLiveViewing($this->sharedUserData['User'])
11365        ){
11366            //-- set list of params for teacher live lessons
11367            $params = array(
11368                'user_id' => !empty($this->sharedUserData['User']['id']) ? $this->sharedUserData['User']['id'] : null,
11369                'payment_plan_id' => !empty($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null,
11370                'currency_code' => !empty($this->sharedUserData['User']['currency_code']) ? $this->sharedUserData['User']['currency_code'] : null,
11371                'user_language' => isset($this->localizeDir) ? $this->localizeDir : $this->sharedUserData['User']['native_language2'],
11372                'pc_view' => true,
11373                'page' => $currentPage,
11374                'template' => isset($data['template']) ? $data['template'] : '',
11375                'mobapp_view' => isset($data['template']) ? true : false,
11376                'limit' => $limit,
11377                'isGuestViwer' => $isGuestViwer,
11378                'isMobile' => !empty($data['isMobile']) ? 1 : 0, // TODO: Add new key-value pair if it is an SP view or mobileApp
11379            );
11380            // Get list of teachers for live lessons
11381            $liveTeacherList = $this->CommonTeacherStatus->liveTeacherList($params);
11382        }
11383        //-- return blank respond
11384        if ( empty($liveTeacherList) ) {
11385            $this->autoRender = false;
11386            $this->layout = false;
11387            return false;
11388        }
11389        // - pass view parameters
11390        $this->set('ajaxDisplay', true);
11391        $this->set('userJpTimeDiffSecond', $userJpTimeDiffSecond);
11392        $this->set('liveTeacherList', $liveTeacherList);
11393        $this->set('studentLessonPriorityTimeDelayInSeconds', (int)$this->studentLessonPriorityTimeDelayInSeconds);
11394        //-- if guest viwer with SP screen
11395        if ( $isGuestViwer && !empty($data['isMobile']) ) {
11396            $this->set('teacherListLiveParameters', $params); //TODO:: Pass the params to live_teacher_banner only in SP_side
11397            return $this->render('/Elements/mobile/live_teacher_banner_list');
11398        }
11399
11400        // - if usage template
11401        if (isset($data['template']) && in_array($data['template'], ["pc_usage", "mobapp_usage"])) {
11402            return $this->render('/Elements/live_teacher_pc_usage_list');
11403
11404        // - else use default
11405        } else {
11406            return $this->render('/Elements/live_teacher_banner_list');
11407        }
11408    }
11409
11410    /**
11411     * @api {get} /user/waiting/sms_questionnaire sms_questionnaire()
11412     * @apiName sms_questionnaire
11413     * @apiGroup Waiting
11414     * @apiDescription Redirects the user to the SMS questionnaire page for a specific teacher in Native Camp. It sets the origin and success URLs in the session and redirects to the SMS questionnaire page.
11415     *
11416     * @apiBody {String} teacherId The ID of the teacher.
11417     * 
11418     * @apiSuccess {String} redirect The URL to redirect to.
11419     *
11420     * @apiSuccessExample {view} Redirect-Response:
11421     *  - Redirects to the /account/sms_questionnaire page.
11422     *
11423     * @apiError {String} error Message indicating the error.
11424     *
11425     * @apiErrorExample {json} Error-Response:
11426     *     {
11427     *         "error": "Invalid request."
11428     *     }
11429     * 
11430     * @apiSampleRequest off
11431     */
11432    public function sms_questionnaire($teacherId = null) {
11433        if (is_null($teacherId)) {
11434            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
11435        }
11436        $data = array(
11437            'origin_url' => '/waiting/detail/'.$teacherId,
11438            'success_url' => '/waiting/detail/'.$teacherId
11439        );        
11440        $this->Session->write($data);
11441        return $this->redirect('/account/sms_questionnaire');
11442    }
11443    
11444    /**
11445     * @api {get} /user/waiting/avatar_sms_questionnaire avatar_sms_questionnaire()
11446     * @apiName avatar_sms_questionnaire
11447     * @apiGroup Waiting
11448     * @apiDescription Redirects the user to the SMS questionnaire page for a specific avatar teacher in Native Camp. It sets the origin and success URLs in the session and redirects to the SMS questionnaire page.
11449     *
11450     * @apiBody {String} teacherId The ID of the avatar teacher.
11451     * 
11452     * @apiSuccess {String} redirect The URL to redirect to.
11453     *
11454     * @apiSuccessExample {view} Redirect-Response:
11455     *  - Redirects to the /account/sms_questionnaire page.
11456     *
11457     * @apiError {String} error Message indicating the error.
11458     *
11459     * @apiErrorExample {json} Error-Response:
11460     *     {
11461     *         "error": "Invalid request."
11462     *     }
11463     * 
11464     * @apiSampleRequest off
11465     */
11466    public function avatar_sms_questionnaire($teacherId = null) {
11467        if (is_null($teacherId)) {
11468            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
11469        }
11470        $data = array(
11471            'origin_url' => '/avatar_detail/'.$teacherId,
11472            'success_url' => '/avatar_detail/'.$teacherId
11473        );        
11474        $this->Session->write($data);
11475        return $this->redirect('/account/sms_questionnaire');
11476    }
11477
11478    /**
11479     * @api {post} /user/waiting/checkCounselorTeacherButtonStatus checkCounselorTeacherButtonStatus()
11480     * @apiName checkCounselorTeacherButtonStatus
11481     * @apiGroup Waiting
11482     * @apiDescription Checks the status of the counselor teacher button for the authenticated user in Native Camp. It returns the availability of the counselor teacher, whether the daily limit is exceeded, and other related data.
11483     *
11484     * @apiBody {Boolean} [dev_test] Indicates whether the request is for development testing.
11485     * @apiBody {Boolean} [customer_support_flg] Indicates whether customer support is enabled.
11486     * 
11487     * @apiSuccess {String} available_teacher The ID of the available teacher.
11488     * @apiSuccess {Boolean} exceed_daily_limit Indicates whether the daily limit is exceeded.
11489     * @apiSuccess {Number} res The result status (0: Not available, 1: Available, 3: Logout).
11490     * @apiSuccess {String} chat_hash The chat hash.
11491     * @apiSuccess {Number} Membership type for checking if the user is not free trial
11492     *
11493     * @apiSuccessExample {json} Success-Response:
11494     *     {
11495     *         "available_teacher": "123",
11496     *         "exceed_daily_limit": 0,
11497     *         "res": 1,
11498     *         "chat_hash": "example_chat_hash",
11499     *            "membership_type": "example_membership_type"
11500     *     }
11501     *
11502     * @apiError {String} error Message indicating the error.
11503     *
11504     * @apiErrorExample {json} Error-Response:
11505     *     {
11506     *         "error": "Invalid request."
11507     *     }
11508     * 
11509     * @apiSampleRequest off
11510     */
11511    public function checkCounselorTeacherButtonStatus() {
11512        $this->autoRender = false;
11513        $this->layout = false;
11514        
11515        $result = 0; // Not available
11516        $devTest = isset($this->request->query['dev_test']) && $this->request->query['dev_test'] ? 1 : 0;
11517
11518        if (isset($this->request->data['customer_support_flg']) && ( $this->request->data['customer_support_flg'] == 'false' || $this->request->data['customer_support_flg'] == false )) {
11519            $customer_support_flg = 0;
11520        }else{
11521            $customer_support_flg = 1;
11522        }
11523        $userId = $this->Auth->user('id');
11524        $teacherId = 0;
11525        $exceedDailyLimit = false;
11526        $chat_hash = null;
11527        $userData = $this->sharedUserData['User'];
11528        if ( $this->request->is('ajax') || $devTest ) {
11529            if ( $userId ) {
11530                $counselorParams = array(
11531                    'user_id' => $userId,
11532                    'user_data' => $userData,
11533                    'customer_support_flg' => $customer_support_flg
11534                );
11535                $data = $this->LessonOnair->checkCounselorTeacherButtonStatus($counselorParams);
11536                $dataObj = json_decode($data,true);
11537                $teacherId = $dataObj['available_teacher'] ?? '';
11538                $exceedDailyLimit = $dataObj['exceed_daily_limit'] ?? '';
11539                $result = $dataObj['res'] ?? '';
11540                $chat_hash = $dataObj['chat_hash'] ?? '';
11541            } else {
11542                $result = 3; // logout
11543            }
11544        }
11545
11546        if($userId){
11547            $csList = ($customer_support_flg == 1) ? $this->Teacher->getCustomerSupportTeachers() : $this->Teacher->getCounselorTeachers();
11548            $csExceedLimitCheck = $this->LessonOnairsLog->checkExceedCSLimit($userId, ($customer_support_flg == 1) ?  $csList['customerSupportId'] : $csList['counselorId']);
11549            if($csExceedLimitCheck){
11550                $exceedDailyLimit = true;
11551            }
11552        }
11553
11554        return json_encode(
11555            array(
11556                'available_teacher' => $teacherId,
11557                'exceed_daily_limit' => ( $exceedDailyLimit ) ? 1 : 0,
11558                'res' => $result,
11559                'chat_hash' => $chat_hash,
11560                'membership_type' => $this->userMembershipType
11561            )
11562        );
11563    }
11564
11565    /**
11566     * @api {get} /user/emergency emergencyLesson()
11567     * @apiName emergencyLesson
11568     * @apiGroup Waiting
11569     * @apiDescription Retrieves the emergency lesson data for the authenticated user in Native Camp. It checks if the user is a Study Sapuri TOS user and returns the preset textbook data.
11570     * 
11571     * @apiSuccess {Object} preset The preset textbook data.
11572     * @apiSuccess {String} preset.textbook_connect_id The ID of the textbook connect.
11573     * @apiSuccess {String} preset.textbook_type The type of the textbook.
11574     * @apiSuccess {Object} searchData The saved search condition data.
11575     * @apiSuccess {String} textbookConnectId The ID of the textbook connect.
11576     * @apiSuccess {String} textbookCategoryTypeId The type ID of the textbook category.
11577     *
11578     * @apiSuccessExample {json} Success-Response
11579     *     {
11580     *         "preset": {
11581     *             "textbook_connect_id": "123",
11582     *             "textbook_type": "1"
11583     *         },
11584     *         "searchData": {...},
11585     *         "textbookConnectId": "123",
11586     *         "textbookCategoryTypeId": "1"
11587     *     }
11588     *
11589     * @apiError {String} error Message indicating the error.
11590     *
11591     * @apiErrorExample {json} Error-Response:
11592     *     {
11593     *         "error": "Not Found"
11594     *     }
11595     * 
11596     * @apiSampleRequest off
11597     */
11598    public function emergencyLesson() {
11599        if (!$this->isStudySapuriTosUser) {
11600            throw new NotFoundException();
11601        }
11602
11603        $presetParams = array("user_id" => $this->Auth->user('id'));
11604        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
11605        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
11606                # for preset
11607                $presetParams['connect_id'] = $preset_data['preset_connect_id'];
11608                $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
11609        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
11610                # use last viewed textbook if no preset data.
11611                $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
11612                $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
11613        }
11614        
11615        # fetch preset 
11616        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
11617        if(!$preset) {
11618                unset($presetParams['connect_id']);
11619                unset($presetParams['last_opened_date']);
11620                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
11621        }
11622
11623        // NC-7228 set series id from saved search condition
11624        $searchData = $this->Cookie->read('searchData');
11625        $this->set('preset', $preset);
11626        $this->set('searchData', $searchData);
11627        $this->set('textbookConnectId', $preset['textbook_connect_id']);
11628        $this->set('textbookCategoryTypeId', $preset['textbook_type']);
11629        return $this->render('/Waiting/emergency_lesson');
11630    }
11631    
11632    /**
11633     * @api {post} /user/waiting/teacherBadgeList teacherBadgeList()
11634     * @apiName teacherBadgeList
11635     * @apiGroup Waiting
11636     * @apiDescription Retrieves the badge list for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the badge list data.
11637     *
11638     * @apiBody {String} teacherId The ID of the teacher.
11639     * @apiBody {Boolean} [sp] Indicates whether the request is from SP.
11640     * 
11641     * @apiSuccess {Object[]} series The series data.
11642     * @apiSuccess {String} series.TextbookCategory.name The name of the textbook category.
11643     * @apiSuccess {String} series.TextbookCategory.id The ID of the textbook category.
11644     * @apiSuccess {String} series.TextbookCategory.type_id The type ID of the textbook category.
11645     * @apiSuccess {String} series.TeacherBadge.textbook_category_id The textbook category ID of the teacher badge.
11646     * @apiSuccess {Boolean} series.TeacherBadge.badge_flg The badge flag of the teacher badge.
11647     * @apiSuccess {String} series.TextbookCategory.image_big_url The image URL of the textbook category.
11648     * @apiSuccess {String} [series.gl_name] The global name of the textbook category (if available).
11649     * @apiSuccess {Object} teacherTbRatings The teacher textbook ratings data.
11650     * @apiSuccess {Number} teacherTbRatings.teacher_textbook_rating The rating of the teacher for the textbook category.
11651     * @apiSuccess {Object[]} titleThresholdTextbookList The title threshold textbook list data.
11652     * @apiSuccess {String} titleThresholdTextbookList.title The title of the threshold.
11653     * @apiSuccess {Number} titleThresholdTextbookList.threshold The threshold value.
11654     *
11655     * @apiSuccessExample {json} Success-Response:
11656     *     {
11657     *         "series": [
11658     *             {
11659     *                 "TextbookCategory": {
11660     *                     "name": "Category Name",
11661     *                     "id": "1",
11662     *                     "type_id": "2",
11663     *                     "image_big_url": "http://example.com/image.jpg"
11664     *                 },
11665     *                 "TeacherBadge": {
11666     *                     "textbook_category_id": "1",
11667     *                     "badge_flg": true
11668     *                 },
11669     *                 "gl_name": "Global Category Name"
11670     *             }
11671     *         ],
11672     *         "teacherTbRatings": {
11673     *             "1": {
11674     *                 "teacher_textbook_rating": 4.5
11675     *             }
11676     *         },
11677     *         "titleThresholdTextbookList": [
11678     *             {
11679     *                 "title": "Expert",
11680     *                 "threshold": 100
11681     *             },
11682     *             {
11683     *                 "title": "Master",
11684     *                 "threshold": 200
11685     *             }
11686     *         ]
11687     *     }
11688     *
11689     * @apiError {String} error Message indicating the error.
11690     *
11691     * @apiErrorExample {json} Error-Response:
11692     *     {
11693     *         "error": "Invalid request."
11694     *     }
11695     * 
11696     * @apiSampleRequest off
11697     */
11698    public function teacherBadgeList() {
11699        $this->layout = "";
11700        if (!$this->request->is('ajax')) { return ; }
11701        
11702        $teacherId = $this->request->data['teacherId'];
11703        if (empty($teacherId)) { return ; }
11704
11705        $fieldArr = array(
11706            'TextbookCategory.name',
11707            'TextbookCategory.id',
11708            'TextbookCategory.type_id',
11709            'TeacherBadge.textbook_category_id',
11710            'TeacherBadge.badge_flg',
11711            'TextbookCategory.type_id',
11712            'TextbookCategory.image_big_url'
11713        );
11714        $joinArr = array(
11715            array(
11716                'table' => 'teacher_badges',
11717                'alias' => 'TeacherBadge',
11718                'type' => 'INNER',
11719                'conditions' => array(
11720                    'TeacherBadge.textbook_category_id = TextbookCategory.id',
11721                    'TeacherBadge.teacher_id' => $teacherId)
11722            )
11723        );
11724
11725        // if the user's language is zh-tw, display chinese textbook badge name
11726        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
11727            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
11728            if($langId){
11729                $joinArr[] = array(
11730                    'type' => 'LEFT',
11731                    'table' => 'global_textbook_categories',
11732                    'alias' => 'GlobalTextbookCategory',
11733                    'conditions' => array(
11734                        'GlobalTextbookCategory.language_id' => $langId,
11735                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
11736                    )
11737                );
11738                $this->TextbookCategory->virtualFields = array(
11739                    'gl_name' => 'GlobalTextbookCategory.gl_name'
11740                );
11741                $fieldArr[] = 'gl_name';
11742            }
11743        }
11744
11745        $conArr = array(
11746            'TextbookCategory.status' => 1,
11747            'TextbookCategory.type_id' => 2
11748        );
11749
11750        # get studydapuri textbooks
11751        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
11752        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
11753            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
11754            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
11755        } elseif ($this->isStudySapuriTosUser) {
11756            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
11757        } else {
11758            $exCat = Configure::read('all_sapuri_textbook_category_types');
11759            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
11760        }
11761
11762        // NJ-5836
11763        $displayRestrictionParams = array(
11764            'lang' => $this->localizeDir
11765        );
11766
11767        // get display restriction setting
11768        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
11769
11770        // NJ-5836 add condition for display restriction
11771        if(isset($displayRestriction['field']) && $displayRestriction['field']){
11772            // set condition for display restriction
11773            $conArr['TextbookCategory.'.$displayRestriction['field']] = 1;
11774        }
11775
11776        //get series and badge
11777        $series = $this->TextbookCategory->find('all', array(
11778            'fields' => $fieldArr,
11779            'conditions' => $conArr,
11780            'joins' => $joinArr,
11781            'order' => array(
11782                'TextbookCategory.sort' => 'ASC'
11783            )
11784        ));
11785
11786        $this->set('series', $series);            
11787        
11788        $teacherTbRatings = array();
11789        if($series && is_array($series)) {
11790            foreach($series as $key => $books){            
11791                $categoryId = $books['TextbookCategory']['id'];
11792                $params = array(
11793                    'teacher_id' =>  (int) $teacherId,
11794                    'textbook_category_id' => (int) $categoryId,
11795                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
11796                );    
11797                $decodeResp = json_decode($this->TeacherTextbookStat->teacherTextbookRating($params));
11798                $teacherTbRatings[$categoryId] = $decodeResp->teacher_textbook_rating;
11799            }
11800        }
11801        $this->set('teacherTbRatings', $teacherTbRatings);
11802
11803        // NJ-17264
11804        $titleThresholdTextbookList = $this->TitleThresholdTeacher->getTitleTresholdPerTextbookCategory(['teacherId' => $teacherId, 'type' => 0]);    
11805
11806        $this->set('titleThresholdTextbookList', $titleThresholdTextbookList);
11807
11808        // new UI
11809        $this->render('teacher_badge_list');
11810        if( isset($this->request->data['sp']) && $this->request->data['sp'] ) {
11811            $this->render('sp_teacher_badge_list');
11812        }
11813    }
11814
11815    /**
11816     * @api {post} /user/waiting/avatarBadgeList avatarBadgeList()
11817     * @apiName avatarBadgeList
11818     * @apiGroup Waiting
11819     * @apiDescription Retrieves the badge list for a specific avatar teacher in Native Camp. It checks if the request is an AJAX request and returns the badge list data.
11820     *
11821     * @apiBody {String} teacher_avatar_id The ID of the avatar teacher.
11822     * @apiBody {Boolean} [sp] Indicates whether the request is from SP.
11823     * 
11824     * @apiSuccess {Object[]} series The series data.
11825     * @apiSuccess {String} series.TextbookCategory.name The name of the textbook category.
11826     * @apiSuccess {String} series.TextbookCategory.id The ID of the textbook category.
11827     * @apiSuccess {String} series.TextbookCategory.type_id The type ID of the textbook category.
11828     * @apiSuccess {String} series.TeacherBadge.textbook_category_id The textbook category ID of the teacher badge.
11829     * @apiSuccess {Boolean} series.TeacherBadge.badge_flg The badge flag of the teacher badge.
11830     * @apiSuccess {String} series.TextbookCategory.image_big_url The image URL of the textbook category.
11831     * @apiSuccess {String} [series.gl_name] The global name of the textbook category (if available).
11832     * @apiSuccess {Object} avatarTbRatings The avatar textbook ratings data.
11833     * @apiSuccess {Number} avatarTbRatings.teacher_textbook_rating The rating of the teacher for the textbook category.
11834     *
11835     * @apiSuccessExample {json} Success-Response:
11836     *     {
11837     *         "series": [
11838     *             {
11839     *                 "TextbookCategory": {
11840     *                     "name": "Category Name",
11841     *                     "id": "1",
11842     *                     "type_id": "2",
11843     *                     "image_big_url": "http://example.com/image.jpg"
11844     *                 },
11845     *                 "TeacherBadge": {
11846     *                     "textbook_category_id": "1",
11847     *                     "badge_flg": true
11848     *                 },
11849     *                 "gl_name": "Global Category Name"
11850     *             }
11851     *         ],
11852     *         "avatarTbRatings": {
11853     *             "1": {
11854     *                 "teacher_textbook_rating": 4.5
11855     *             }
11856     *         }
11857     *     }
11858     *
11859     * @apiError {String} error Message indicating the error.
11860     *
11861     * @apiErrorExample {json} Error-Response:
11862     *     {
11863     *         "error": "Invalid request."
11864     *     }
11865     * 
11866     * @apiSampleRequest off
11867     */
11868    public function avatarBadgeList() {
11869        $this->layout = "";
11870
11871        if (!$this->request->is('ajax')) { return; }
11872        
11873        $avatarId = Sanitize::escape($this->request->data['teacher_avatar_id']);
11874
11875        if (empty($avatarId)) { return; }
11876
11877        $fieldArr = array(
11878            'TextbookCategory.name',
11879            'TextbookCategory.id',
11880            'TextbookCategory.type_id',
11881            'TeacherBadge.textbook_category_id',
11882            'TeacherBadge.badge_flg',
11883            'TextbookCategory.type_id',
11884            'TextbookCategory.image_big_url'
11885        );
11886        $joinArr = array(
11887            array(
11888                'table' => 'teacher_badges',
11889                'alias' => 'TeacherBadge',
11890                'type' => 'INNER',
11891                'conditions' => array('TeacherBadge.textbook_category_id = TextbookCategory.id', 'TeacherBadge.teacher_id' => $avatarId)
11892            )
11893        );
11894
11895        // if the user's language is zh-tw, display chinese textbook badge name
11896        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
11897            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
11898            if($langId){
11899                $joinArr[] = array(
11900                    'type' => 'LEFT',
11901                    'table' => 'global_textbook_categories',
11902                    'alias' => 'GlobalTextbookCategory',
11903                    'conditions' => array(
11904                        'GlobalTextbookCategory.language_id' => $langId,
11905                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
11906                    )
11907                );
11908                $this->TextbookCategory->virtualFields = array(
11909                    'gl_name' => 'GlobalTextbookCategory.gl_name'
11910                );
11911                $fieldArr[] = 'gl_name';
11912            }
11913        }
11914
11915        $conArr = array(
11916            'TextbookCategory.status' => 1,
11917            'TextbookCategory.type_id' => 2
11918        );
11919
11920        # get studydapuri textbooks
11921        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
11922        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
11923            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
11924            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
11925        } elseif ($this->isStudySapuriTosUser) {
11926            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
11927        } else {
11928            $exCat = Configure::read('all_sapuri_textbook_category_types');
11929            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
11930        }
11931
11932        // NJ-5836
11933        $displayRestrictionParams = array(
11934            'lang' => $this->localizeDir
11935        );
11936
11937        // get display restriction setting
11938        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
11939
11940        // NJ-5836 add condition for display restriction
11941        if(isset($displayRestriction['field']) && $displayRestriction['field']){
11942            // set condition for display restriction
11943            $conArr['TextbookCategory.'.$displayRestriction['field']] = 1;
11944        }
11945
11946        //get series and badge
11947        $series = $this->TextbookCategory->find('all', array(
11948            'fields' => $fieldArr,
11949            'conditions' => $conArr,
11950            'joins' => $joinArr,
11951            'order' => array(
11952                'TextbookCategory.sort' => 'ASC'
11953            )
11954        ));
11955
11956        $this->set('series', $series);
11957
11958        $avatarTbRatings = array();
11959        if($series && is_array($series)) {
11960            foreach($series as $key => $books){            
11961                $categoryId = $books['TextbookCategory']['id'];
11962                $params = array(
11963                    'avatar_id' => $avatarId,
11964                    'textbook_category_id' => (int) $categoryId,
11965                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
11966                );    
11967                $decodeResp = json_decode($this->TeacherTextbookStat->avatarTextbookRating($params));
11968                $avatarTbRatings[$categoryId] = $decodeResp->teacher_textbook_rating;
11969            }
11970        }
11971        $this->set('avatarTbRatings', $avatarTbRatings);
11972        
11973        if(isset($this->request->data['sp']) && $this->request->data['sp']) {
11974            $this->set('avatar_sp', 1);
11975            $this->render('sp_teacher_badge_list');
11976        }
11977
11978    }    
11979
11980    /**
11981     * @api {post} /user/waiting/teacherOccupation teacherOccupation()
11982     * @apiName teacherOccupation
11983     * @apiGroup Waiting
11984     * @apiDescription Retrieves the occupation history of a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the teacher occupation data.
11985     *
11986     * @apiBody {String} teacherId The ID of the teacher.
11987     * 
11988     * @apiSuccess {Object[]} teacherOccupation The teacher occupation data.
11989     * @apiSuccess {String} teacherOccupation.id The ID of the occupation detail.
11990     * @apiSuccess {String} teacherOccupation.teacher_id The ID of the teacher.
11991     * @apiSuccess {String} teacherOccupation.occupation The occupation of the teacher.
11992     * @apiSuccess {String} teacherOccupation.start_date The start date of the occupation.
11993     * @apiSuccess {String} teacherOccupation.end_date The end date of the occupation.
11994     * @apiSuccess {String} lang The language code for the page.
11995     *
11996     * @apiSuccessExample {json} Success-Response:
11997     *     {
11998     *         "teacherOccupation": [
11999     *             {
12000     *                 "id": "1",
12001     *                 "teacher_id": "123",
12002     *                 "occupation": "Software Engineer",
12003     *                 "start_date": "2020-01-01",
12004     *                 "end_date": "2021-01-01"
12005     *             },
12006     *             {
12007     *                 "id": "2",
12008     *                 "teacher_id": "123",
12009     *                 "occupation": "Project Manager",
12010     *                 "start_date": "2021-02-01",
12011     *                 "end_date": "2022-01-01"
12012     *             }
12013     *         ],
12014     *         "lang": "en"
12015     *     }
12016     *
12017     * @apiError {String} error Message indicating the error.
12018     *
12019     * @apiErrorExample {json} Error-Response:
12020     *     {
12021     *         "error": "Invalid request."
12022     *     }
12023     * 
12024     * @apiSampleRequest off
12025     */
12026    public function teacherOccupation() {
12027        $this->layout = "";
12028        if (!$this->request->is('ajax')) { return ; }
12029        
12030        $teacherId = $this->request->data['teacherId'];
12031        if (empty($teacherId)) { return ; }
12032
12033        //NC-9215 get teacher occupation history
12034        $teacherOccupation = ClassRegistry::init('TeacherOccupationDetail')->getTeacherOccupationDetails($teacherId);
12035        $this->set('teacherOccupation', $teacherOccupation);
12036        $lang = isset($this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language');
12037        $this->set('lang', $lang);        
12038
12039        $this->render('teacher_occupation');
12040    }
12041
12042     //only used in this class controller
12043     //Retrieves the features of a specific teacher in Native Camp. It checks if the request is an AJAX request or if it is called from SP, and returns the teacher features data.
12044    public function teacherFeatures($sp = false, $teacherId = null) {
12045        $this->autoRender = false;
12046        $this->layout = false;
12047        if ($this->request->is('ajax') || $sp) {
12048            $teacherId = $this->request->data['teacherId'] ?? $teacherId;
12049            if (empty($teacherId)) { return ; }
12050    
12051            $feature = $this->TeacherFeature->find('first', array(
12052                'conditions' =>  array(
12053                    'TeacherFeature.teacher_id' => $teacherId
12054                )
12055            ));
12056            return json_encode(isset($feature['TeacherFeature']) ? $feature['TeacherFeature'] : array());
12057        } return;
12058    }
12059
12060    /**
12061     * @api {post} /user/waiting/getSelfReviews getSelfReviews()
12062     * @apiName getSelfReviews
12063     * @apiGroup Waiting
12064     * @apiDescription Retrieves the self-reviews for a specific teacher and user in Native Camp. It checks if the request is an AJAX request and returns the self-reviews data.
12065     *
12066     * @apiBody {String} teacherId The ID of the teacher.
12067     * @apiBody {String} userId The ID of the user.
12068     * 
12069     * @apiSuccess {Object[]} selfReviews The self-reviews data.
12070     * @apiSuccess {String} selfReviews.review The review text.
12071     * @apiSuccess {Number} selfReviews.rating The rating given by the user.
12072     * @apiSuccess {String} selfReviews.date The date of the review.
12073     * @apiSuccess {Number} selfLessonCount The count of lessons taken by the user with the teacher.
12074     * @apiSuccess {Number} daysPast The number of days past since the user's last lesson with the teacher.
12075     * @apiSuccess {String} lessonHistoryTeacherId The ID of the teacher for the lesson history.
12076     *
12077     * @apiSuccessExample {json} Success-Response:
12078     *     {
12079     *         "selfReviews": [
12080     *             {
12081     *                 "review": "Great lesson!",
12082     *                 "rating": 5,
12083     *                 "date": "2023-01-01"
12084     *             },
12085     *             {
12086     *                 "review": "Very helpful.",
12087     *                 "rating": 4,
12088     *                 "date": "2023-01-02"
12089     *             }
12090     *         ],
12091     *         "selfLessonCount": 5,
12092     *         "daysPast": 10,
12093     *         "lessonHistoryTeacherId": "123"
12094     *     }
12095     *
12096     * @apiError {String} error Message indicating the error.
12097     *
12098     * @apiErrorExample {json} Error-Response:
12099     *     {
12100     *         "error": "Invalid request."
12101     *     }
12102     * 
12103     * @apiSampleRequest off
12104     */
12105    public function getSelfReviews() {
12106        $this->layout = "";
12107        $this->autoRender = false;
12108        if (!$this->request->is('ajax')) { return ; }
12109        
12110        $teacherId = $this->request->data['teacherId'] ?? null;
12111        if (empty($teacherId)) { return ; }
12112
12113        $userId = $this->request->data['userId'] ?? null;
12114
12115        //get own reviews
12116        $selfReviews = array();
12117        $selfLessonCount = 0;
12118        $daysPast = 0;
12119        if ($userId) {
12120            $selfReviews = $this->getUserReviews($userId, $teacherId);
12121            $selfLessonCount = $this->LessonOnairsLog->countOwnLessons($userId, $teacherId);
12122            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
12123        }
12124
12125        $this->set('selfReviews', $selfReviews);
12126        $this->set('selfLessonCount', $selfLessonCount);
12127        $this->set('daysPast', $daysPast);
12128        $this->set('lessonHistoryTeacherId',$teacherId);
12129
12130        $this->render('/Elements/self_review');
12131    }
12132
12133    /**
12134     * @api {post} /user/waiting/getGenerationRating getGenerationRating()
12135     * @apiName getGenerationRating
12136     * @apiGroup Waiting
12137     * @apiDescription Retrieves the generation rating data for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the rating data.
12138     *
12139     * @apiBody {String} teacherId The ID of the teacher.
12140     * @apiBody {Boolean} [isAvatar] Indicates whether the teacher is an avatar.
12141     * 
12142     * @apiSuccess {Object} rates The generation rating data.
12143     * @apiSuccess {Number} rates.count The total number of ratings.
12144     * @apiSuccess {Number} rates.one_star The number of one-star ratings.
12145     * @apiSuccess {Number} rates.two_star The number of two-star ratings.
12146     * @apiSuccess {Number} rates.three_star The number of three-star ratings.
12147     * @apiSuccess {Number} rates.four_star The number of four-star ratings.
12148     * @apiSuccess {Number} rates.five_star The number of five-star ratings.
12149     * @apiSuccess {Object} rateBreakdown The breakdown of the generation rating data.
12150     * @apiSuccess {Number} rateBreakdown.weekly_average The weekly average rating.
12151     * @apiSuccess {Number} rateBreakdown.monthly_average The monthly average rating.
12152     * @apiSuccess {Number} rateBreakdown.total_average The total average rating.
12153     *
12154     * @apiSuccessExample {json} Success-Response:
12155     *     {
12156     *         "rates": {
12157     *             "count": 100,
12158     *             "one_star": 10,
12159     *             "two_star": 20,
12160     *             "three_star": 30,
12161     *             "four_star": 25,
12162     *             "five_star": 15
12163     *         },
12164     *         "rateBreakdown": {
12165     *             "weekly_average": 4.2,
12166     *             "monthly_average": 4.0,
12167     *             "total_average": 4.1
12168     *         }
12169     *     }
12170     *
12171     * @apiError {String} error Message indicating the error.
12172     *
12173     * @apiErrorExample {json} Error-Response:
12174     *     {
12175     *         "error": "Invalid request."
12176     *     }
12177     * 
12178     * @apiSampleRequest off
12179     */
12180    public function getGenerationRating() {
12181        $this->layout = "";
12182        $this->autoRender = false;
12183        
12184        if (!$this->request->is('ajax')) { return ; }
12185        
12186        $teacherId = Sanitize::escape($this->request->data['teacherId']);
12187        if (empty($teacherId)) { return ; }
12188
12189        $isAvatar = (isset($this->request->data['isAvatar']) && $this->request->data['isAvatar']) ? true : false;
12190        if($isAvatar){
12191            $teacherId = $this->Teacher->getAvatarTeacherId(array('avatar_id' => $teacherId));
12192            $rating = $this->UsersClassEvaluation->getRatings($teacherId, true);
12193        }
12194
12195        $rating = $this->UsersClassEvaluation->getRatings($teacherId, true);
12196        if ($rating) {
12197            $rates = new UsersClassEvaluationTable($rating['UsersClassEvaluation']);
12198            $rateBreakdown = new UsersClassEvaluationTable($rating['TeacherWeeklyRating']);
12199        }
12200        $this->set('rates', $rates ?? []);        
12201        $this->set('rateBreakdown', $rateBreakdown ?? []);        
12202
12203        $this->render('teacher_generation_rating');
12204    }
12205
12206    /**
12207     * @api {post} /user/api/getGenerationRating getGenerationRatingAPI()
12208     * @apiName getGenerationRatingAPI
12209     * @apiGroup Waiting
12210     * @apiDescription Retrieves the generation rating data for a specific teacher in Native Camp. It checks the teacher ID and user token, and returns the rating data.
12211     *
12212     * @apiBody {String} teacher_id The ID of the teacher.
12213     * @apiBody {String} users_api_token The API token of the user.
12214     * 
12215     * @apiSuccess {Object} generationData The generation rating data. (0: 20, 1: 30, 2: 50)
12216     *
12217     * @apiSuccessExample {json} Success-Response:
12218     *     {
12219     *         "generationData": {
12220     *             "0": 20,
12221     *             "1": 30,
12222     *             "2": 50
12223     *         }
12224     *     }
12225     *
12226     * @apiError {Object} error The error details.
12227     * @apiError {String} error.id The error ID.
12228     * @apiError {String} error.message The error message.
12229     *
12230     * @apiErrorExample {json} Error-Response (Bad Request):
12231     *     {
12232     *         "error": {
12233     *             "id": "invalid_teacher_id",
12234     *             "message": "teacher_id is invalid"
12235     *         }
12236     *     }
12237      * @apiErrorExample {json} Error-Response (Unauthorized):
12238     *     {
12239     *         "error": {
12240     *             "id": "invalid_token",
12241     *             "message": "users_api_token is invalid"
12242     *         }
12243     *     }
12244     * 
12245     * @apiSampleRequest off
12246     */
12247    public function getGenerationRatingAPI(){
12248        $this->autoRender = false;
12249        $this->layout = false;
12250        $data = json_decode($this->request->input(), true);
12251        $teacherId = isset($data['teacher_id']) ? $data['teacher_id'] : '';
12252        if (empty($teacherId)) { 
12253            $response['error']['id'] = _('invalid_teacher_id');
12254            $response['error']['message'] = __('teacher_id is invalid');
12255            return json_encode($response);
12256        }
12257        $userToken = isset($data['users_api_token']) ? $data['users_api_token'] : '';
12258        $userData = $this->User->getUserDataByApiToken($userToken);
12259        if(!$userData) {
12260            $response['error']['id'] = _('invalid_token');
12261            $response['error']['message'] = __('users_api_token is invalid');
12262            return json_encode($response);
12263        }
12264        $rating = $this->UsersClassEvaluation->getRatings($teacherId, true);
12265        if ($rating) {
12266            $rates = new UsersClassEvaluationTable($rating['UsersClassEvaluation']);
12267            $rateBreakdown = new UsersClassEvaluationTable($rating['TeacherWeeklyRating']);
12268        }
12269        $ctr = 0;
12270        foreach($rates as $rate){
12271            $generationData[$ctr] = ($rate / $rates->count) * 100; // get percentages for data
12272            $ctr++;
12273        }
12274        //remove count element at the end
12275        array_pop($generationData);
12276        return json_encode($generationData);
12277    }
12278
12279    public function getUserMemo(){
12280        $this->autoRender = false;
12281        $this->layout = false;
12282        $data = json_decode($this->request->input(), true);
12283        $teacherId = isset($data['teacher_id']) ? $data['teacher_id'] : '';
12284        if (empty($teacherId)) { 
12285            $response['error']['id'] = _('invalid_teacher_id');
12286            $response['error']['message'] = __('teacher_id is invalid');
12287            return json_encode($response);
12288        }
12289        $userToken = isset($data['users_api_token']) ? $data['users_api_token'] : '';
12290        $userData = $this->User->getUserDataByApiToken($userToken);
12291        if(!$userData) {
12292            $response['error']['id'] = _('invalid_token');
12293            $response['error']['message'] = __('users_api_token is invalid');
12294            return json_encode($response);
12295        }
12296
12297        $getKeepMemo = $this->UsersMemo->find('first', array(
12298            'fields' => array(
12299                'id',
12300                'memo'
12301            ),
12302            'conditions' => array(
12303                'user_id' => $userData['id'],
12304                'teacher_id' => $teacherId,
12305                'type' => 0
12306            ),
12307            'order' => array('created DESC'),
12308        ));
12309        $memoData['id'] = $getKeepMemo['UsersMemo']['id'];
12310        $memoData['memo'] = $getKeepMemo['UsersMemo']['memo'];
12311        
12312        return json_encode($memoData);
12313    }
12314
12315    /**
12316     * @api {post} /user/waiting/getReservationCancellationBreakdown getReservationCancellationBreakdown()
12317     * @apiName getReservationCancellationBreakdown
12318     * @apiGroup Waiting
12319     * @apiDescription Retrieves the reservation and cancellation breakdown for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the reservation and cancellation data.
12320     *
12321     * @apiBody {String} teacherId The ID of the teacher.
12322     * 
12323     * @apiSuccess {Object} reserveAndCancel The reservation and cancellation breakdown data.
12324     * @apiSuccess {Number} reserveAndCancel.this_month_reserved The number of reservations made this month.
12325     * @apiSuccess {Number} reserveAndCancel.last_month_reserved The number of reservations made last month.
12326     * @apiSuccess {Number} reserveAndCancel.this_month_cancelled The number of reservations cancelled this month.
12327     * @apiSuccess {Number} reserveAndCancel.last_month_cancelled The number of reservations cancelled last month.
12328     * @apiSuccess {Number} reserveAndCancel.this_month_cancellation_rate The cancellation rate this month.
12329     * @apiSuccess {Number} reserveAndCancel.last_month_cancellation_rate The cancellation rate last month.
12330     * 
12331     * @apiSuccessExample {json} Success-Response:
12332     *     {
12333     *         "reserveAndCancel": {
12334     *             "this_month_reserved": 10,
12335     *             "last_month_reserved": 20,
12336     *             "this_month_cancelled": 5,
12337     *             "last_month_cancelled": 10,
12338     *             "this_month_cancellation_rate": 0.5
12339     *         }
12340     *     }
12341     *
12342     * @apiError {String} error Message indicating the error.
12343     *
12344     * @apiErrorExample {json} Error-Response:
12345     *     {
12346     *         "error": "Invalid request."
12347     *     }
12348     * 
12349     * @apiSampleRequest off
12350     */
12351    public function getReservationCancellationBreakdown() {
12352        $this->autoRender = false;
12353        $this->layout = false;
12354        if (!$this->request->is('ajax')) { return ; }
12355        
12356        $teacherId = $this->request->data['teacherId'];
12357        if (empty($teacherId)) { return ; }
12358
12359        //reservation and cancellation breakdown
12360        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
12361        return json_encode(isset($reserveAndCancel) ? $reserveAndCancel : array());
12362    }
12363
12364    // NJ-22649 transfer functionality from lesson-finish
12365    //not used function
12366    public function getActiveCampaign($params = array()) {
12367        $counseling_flg = (isset($params['counseling_flg']) && $params['counseling_flg']) ? true : false;
12368        $avatar_flg = (isset($params['avatar_flg']) && $params['avatar_flg']) ? true : false;
12369        $chat_hash = (isset($params['chat_hash']) && $params['chat_hash']) ? $params['chat_hash'] : '';
12370        $memberType = (isset($params['memberType']) && $params['memberType']) ? $params['memberType'] : 'student';
12371
12372        $campaignTerm = false;
12373        $modalCampaignType = '';
12374        $campaignPageRecord = '';
12375        $userId = $this->Auth->user('id');
12376        $userData = new UserTable($this->sharedUserData['User']);
12377
12378        $campaignSetting = ClassRegistry::init('CampaignSettingTable');
12379        $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12380        $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12381
12382        //Spring Callan Campaign
12383        $campaignSpringCallanPeriodFrom = Configure::read('campaign_config.callanFirstTime.period.start');
12384        $campaignSpringCallanPeriodTo = Configure::read('campaign_config.callanFirstTime.period.reservation_end');
12385        $campaignSpringCallan = $this->showCampaignModal($campaignSpringCallanPeriodFrom, $campaignSpringCallanPeriodTo);
12386
12387        //Campaign to talk with teachers from all over the world
12388        $campaignGlobalLesson = ClassRegistry::init('CampaignSettingTable')->globalLesson(array('user_id' => $userId, 'type' => 1)); //Check campaign duration date and if not sapuri user
12389        $sixthAnniv3Campaign = ClassRegistry::init('CampaignSettingTable')->sixthAnniv3(array('user_id' => $userId));
12390
12391        //Go to travel campaign
12392        $goToTravelDateArr = Configure::read('campaign_config.gototravel.period');
12393        $goToTravelCampaign = $this->showCampaignModal($goToTravelDateArr['start'], $goToTravelDateArr['end']);
12394
12395        //Alvark Collaboration Campaign
12396        $alvarkCollabCampaign = false;
12397        $alvarkCollabDateArr = Configure::read('campaign_config.alvark_collaboration.period');
12398        $alvarkCollabCheckDate = $this->showCampaignModal($alvarkCollabDateArr['start'], $alvarkCollabDateArr['end']);
12399        if (
12400            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.alvark_collaboration.valid_memberships')) 
12401            && $userData->currency_code == Configure::read('default.user_currency')
12402            && $alvarkCollabCheckDate
12403            && $this->localizeDir == Configure::read('default.user_language')
12404        ) {
12405            $alvarkCollabCampaign = true;
12406        }
12407
12408        // Campaign Settings Modal
12409        $currStr = $userData->currency_code;
12410        $langId = ClassRegistry::init("CountryCode")->getUserLanguageId($userData->native_language2);
12411        $today = date('Y-m-d H:i:s');
12412        $conditions = array(
12413            'user_plan_type' => $userData->getMembershipTypeIndex(),
12414            'plan_types' => Configure::read('campaign_settings.plan_types'),
12415            'is_sapuri_user' => $userData->isStudySapuri(),
12416            'corporate_user_types' => Configure::read('campaign_settings.corporates'),
12417            'free_user_type' => Configure::read('campaign_settings.free_user_type'),
12418        );
12419
12420        $campaignUserPlanType = $userData->getUserPlanType($conditions);
12421        $this->log("[CampaignSettingsModal][after_lesson] conditions -> " .  json_encode($conditions), "debug");
12422        $campaignSettings = null;
12423        if ((isset($campaignUserPlanType['plan_type']) && $campaignUserPlanType['plan_type']) &&
12424            (isset($campaignUserPlanType['user_type']) && $campaignUserPlanType['user_type'])
12425        ) {
12426            $campaignSettingsModel = ClassRegistry::init('CampaignSettings');
12427            $campaignSettings = $campaignSettingsModel->getActiveAndNotEnded(array(
12428                'fields' => array(
12429                    'CampaignSettings.id',
12430                    'CampaignSettings.modal_html',
12431                    'CampaignSettings.pc_url',
12432                    'CampaignSettings.image_url_pc'
12433                ),
12434                'conditions' => array(
12435                    'CampaignSettings.promo_end >=' => $today,
12436                    'CampaignSettings.status_flag' => 1,
12437                    'CampaignSettings.promo_event_type' => 1, // after lesson
12438                    'CampaignSettings.pc_url IS NOT NULL',
12439
12440                    // os
12441                    array(
12442                        'OR' => array(
12443                            array('CampaignSettings.promo_os LIKE' => '%1%'), // pc
12444                            array('CampaignSettings.promo_os LIKE' => '%0%'), // all
12445                        )
12446                    ),
12447
12448                    // login status
12449                    array(
12450                        'OR' => array(
12451                            array('CampaignSettings.promo_login_status LIKE' => '%1%'), // sign in
12452                            array('CampaignSettings.promo_login_status LIKE' => '%0%'), // all
12453                        )
12454                    ),
12455
12456                    // Plan type
12457                    array(
12458                        'OR' => array(
12459                            array('CampaignSettings.promo_plan_type LIKE' => '%'.$campaignUserPlanType['plan_type'].'%'),
12460                            array('CampaignSettings.promo_plan_type LIKE' => '%0%'), // ALL
12461                        )
12462                    ),
12463
12464                    // User type
12465                    array(
12466                        'OR' => array(
12467                            array('CampaignSettings.promo_user_type LIKE' => '%'.$campaignUserPlanType['user_type'].'%'),
12468                            array('CampaignSettings.promo_user_type LIKE' => '%0%') // ALL
12469                        )
12470                    ),
12471
12472                    // Currency and Language
12473                    array(
12474                        "(SELECT COUNT(*) FROM `campaign_setting_currency` WHERE `CampaignSettings`.`id` = `campaign_setting_currency`.`campaign_setting_id` AND `campaign_setting_currency`.`currency_code` = '".$currStr."') > 0"
12475                    ),
12476                    array(
12477                        "(SELECT COUNT(*) FROM `campaign_setting_language` WHERE `CampaignSettings`.`id` = `campaign_setting_language`.`campaign_setting_id` AND `campaign_setting_language`.`language_id` = '".$langId."') > 0"
12478                    )
12479                ),
12480                'order' => 'CampaignSettings.promo_start ASC'
12481            ));
12482        }
12483
12484        //Marines Collaboration Campaign
12485        $marinesCollabCampaign = false;
12486        $marinesCollabDateArr = Configure::read('campaign_config.going_global_marines_collaboration.period');
12487        $marinesCollabCheckDate = $this->showCampaignModal($marinesCollabDateArr['start'], $marinesCollabDateArr['end']);
12488        if (
12489            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.going_global_marines_collaboration.valid_memberships')) 
12490            && $marinesCollabCheckDate
12491            && $this->localizeDir == Configure::read('default.user_language')
12492        ) {
12493            $marinesCollabCampaign = true;
12494        }
12495
12496        // //Daily News Campaign
12497        // $dailyNewsCampaign = false;
12498        // $dailyNewsDateArr = Configure::read('campaign_config.daily_news.period');
12499        // $dailyNewsCheckDate = $this->showCampaignModal($dailyNewsDateArr['start'], $dailyNewsDateArr['end']);
12500        // if (
12501        //     in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.daily_news.valid_memberships')) 
12502        //     && $dailyNewsCheckDate
12503        // ) {
12504        //     $dailyNewsCampaign = true;
12505        // }
12506
12507        //Favorite Teacher Campaign
12508        $favoriteTeacherCampaign = false;
12509        $favoriteTeacherDateArr = Configure::read('campaign_config.favorite_teacher.period');
12510        $favoriteTeacherCheckDate = $this->showCampaignModal($favoriteTeacherDateArr['start'], $favoriteTeacherDateArr['end']);
12511        if (
12512            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.favorite_teacher.valid_memberships')) 
12513            && $favoriteTeacherCheckDate
12514        ) {
12515            $favoriteTeacherCampaign = true;
12516        }
12517
12518        //Family Plan Campaign
12519        $familyPlanCampaign = false;
12520        $familyPlanDateArr = Configure::read('campaign_config.family_plan.period');
12521        $familyPlanCheckDate = $this->showCampaignModal($familyPlanDateArr['start'], $familyPlanDateArr['end']);
12522        if (
12523            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.family_plan.valid_memberships')) 
12524            && $familyPlanCheckDate
12525        ) {
12526            $familyPlanCampaign = true;
12527        }
12528
12529        //Christmas Campaign
12530        $christmasCampaign = false;
12531        $christmasDateArr = Configure::read('campaign_config.christmas.period');
12532        $christmasCheckDate = $this->showCampaignModal($christmasDateArr['start'], $christmasDateArr['end']);
12533        if (
12534            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.christmas.valid_memberships')) 
12535            && $christmasCheckDate
12536        ) {
12537            $christmasCampaign = true;
12538        }
12539
12540        //New year Part 1 Campaign
12541        $newYearPart1Campaign = false;
12542        $newYearPart1DateArr = Configure::read('campaign_config.new_year_part_1.period');
12543        $newYearPart1CheckDate = $this->showCampaignModal($newYearPart1DateArr['start'], $newYearPart1DateArr['end']);
12544        if (
12545            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.new_year_part_1.valid_memberships')) 
12546            && ($userData->admin_flg || $newYearPart1CheckDate) 
12547            && $this->localizeDir == Configure::read('default.user_language')
12548        ) {
12549            $newYearPart1Campaign = true;
12550        }
12551
12552        //New grammar Campaign
12553        $newGrammarCampaign = false;
12554        $newGrammarDateArr = Configure::read('campaign_config.new_grammar.period');
12555        $newGrammarCheckDate = $this->showCampaignModal($newGrammarDateArr['start'], $newGrammarDateArr['end']);
12556        if (
12557            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.new_grammar.valid_memberships')) 
12558            && $newGrammarCheckDate
12559        ) {
12560            $newGrammarCampaign = true;
12561        }
12562
12563        //Alvark collab Campaign
12564        $alvarkCollab2Campaign = false;
12565        $alvarkCollab2DateArr = Configure::read('campaign_config.alvark_collab_2.period');
12566        $alvarkCollab2CheckDate = $this->showCampaignModal($alvarkCollab2DateArr['start'], $alvarkCollab2DateArr['end']);
12567        if (
12568            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.alvark_collab_2.valid_memberships')) 
12569            && $alvarkCollab2CheckDate
12570            && $this->localizeDir == Configure::read('default.user_language')
12571        ) {
12572            $alvarkCollab2Campaign = true;
12573        }
12574
12575        //Golden Week NC Campaign
12576        $goldenWeekNCChallengeCampaign = false;
12577        $goldenWeekNCChallengeDateArr = Configure::read('campaign_config.golden_week_nc_challenge.period');
12578        $goldenWeekNCChallengeCheckDate = $this->showCampaignModal($goldenWeekNCChallengeDateArr['start'], $goldenWeekNCChallengeDateArr['end']);
12579        if (
12580            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.golden_week_nc_challenge.valid_memberships')) 
12581            && $goldenWeekNCChallengeCheckDate
12582        ) {
12583            $goldenWeekNCChallengeCampaign = true;
12584        }
12585
12586        if ($campaignSpringCallan) {
12587            $campaignTerm = $campaignSpringCallan;
12588            $modalCampaignType = 'campaign_callan_half_spring';
12589            $campaignPageRecord = 'callan_half_spring_record';
12590            // check if not a sapuri student
12591            $userData = new UserTable( $this->sharedUserData[ 'User' ] );
12592            if (in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.callanFirstTime.membership'))) {        
12593                /* count callan lesson taken within the campaign period */
12594                $countCallanLesson = ClassRegistry::init('CampaignSettingTable')->callanMarathonCampaign(array(
12595                    'user_id' => $this->Auth->user("id"),
12596                    'date_period' => array(
12597                            Configure::read('campaign_config.callanFirstTime.period.start'),
12598                            Configure::read('campaign_config.callanFirstTime.period.reservation_end')
12599                        ),
12600                    'tb_category_id' => Configure::read('campaign_config.callanFirstTime.textbook_category')
12601                ));
12602                $response['countCallanLesson'] = $countCallanLesson;
12603            }
12604
12605        } else if ($campaignGlobalLesson) {
12606            //If not counseling: display modal stamp
12607            if (!$counseling_flg) {
12608                $campaignTerm = $campaignGlobalLesson;
12609                $modalCampaignType = 'campaign_global_lesson';
12610                $campaignPageRecord = 'global_lesson_record';
12611            }
12612        } else if ($sixthAnniv3Campaign) {
12613            $campaignTerm = $sixthAnniv3Campaign;
12614            $modalCampaignType = 'campaign_sixth_anniv_3';
12615            $campaignPageRecord = 'sixth_anniv_record';
12616
12617        //Go to travel campaign
12618        } else if ($goToTravelCampaign) {
12619            if (!$counseling_flg) {
12620                $userData = new UserTable( $this->sharedUserData[ 'User' ] );
12621                $stampAchieved = array();
12622                if (!in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.gototravel.membership_invalid'))) {
12623                    // get student achieved lesson stamps
12624                    $stampAchieved = ClassRegistry::init('CampaignSettingTable')->camapaignGoToTravelTbStamp(array(
12625                        'user_id' => $this->Auth->user( 'id' ),
12626                        'start_time' => Configure::read('campaign_config.gototravel.period.start'),
12627                        'end_time' => Configure::read('campaign_config.gototravel.period.end'),
12628                        'tb_connect_ids' => array_values(array_flip(Configure::read('campaign_config.gototravel.textbook_connect'))),
12629                        'lesson_min_time' => Configure::read('campaign_config.gototravel.lesson_time')
12630                    ));
12631                    $stampAchieved = is_array($stampAchieved) ? array_values($stampAchieved) : $stampAchieved;
12632                    $response['stampAchieved'] = $stampAchieved;
12633                    $modalCampaignType = 'campaign_gototravel_is_back';
12634                    $campaignPageRecord = 'gototravel_is_back_record';
12635                    $campaignTerm = $goToTravelCampaign;
12636                }
12637            }
12638        } else if ($alvarkCollabCampaign) {
12639            if (!$counseling_flg) {
12640                $cst = ClassRegistry::init('CampaignSettingTable');
12641                $campaignStamps = $cst->alvarkCollaboration(
12642                    array(
12643                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12644                        'type' => 1,
12645                    )
12646                );
12647                $response['campaignStamps'] = $campaignStamps;
12648                $modalCampaignType = 'campaign_going_global_alvark_live';
12649                $campaignTerm = $alvarkCollabCampaign;
12650            }
12651        } 
12652
12653        if ($campaignSettings) {
12654            $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12655            $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12656            $showCampaignSettingsCampModal = array();
12657            foreach ($campaignSettings as $key => $value) {
12658                $id = $value['CampaignSettings']['id'];
12659                if (!in_array($id, $dontShowCampaignModals)) {
12660                    $showCampaignSettingsCampModal[] = $id;
12661                }
12662            }
12663            $response['campaignSettings'] = $campaignSettings;
12664            $response['showCampaignSettingsCampModal'] = $showCampaignSettingsCampModal;
12665            $response['campaignSettingsAfterLeson'] = true;
12666        } else if ($marinesCollabCampaign) {
12667            if (!$counseling_flg) {
12668                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12669                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12670                $marinesCollabCampPeriod = Configure::read('campaign_config.going_global_marines_collaboration.period');
12671                $marinesCollabCampaignSettingId = Configure::read('campaign_config.going_global_marines_collaboration.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12672    
12673                $response['marinesCollabCampaignSettingId'] = $marinesCollabCampaignSettingId;
12674                $response['marinesCollabCampaign'] = $marinesCollabCampaign;
12675                $response['showMarinesCollabCampModal'] = (!in_array($marinesCollabCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12676
12677                $cst = ClassRegistry::init('CampaignSettingTable');
12678                $campaignStamps = $cst->marinesCollaboration(
12679                    array(
12680                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12681                        'type' => 1,
12682                        'display_type' => 1,
12683                    )
12684                );
12685                $response['campaignStamps'] = $campaignStamps;
12686                $modalCampaignType = 'campaign_going_global_marines_live';
12687                $campaignTerm = $marinesCollabCampaign;
12688            }
12689        }
12690        // if ($dailyNewsCampaign) {
12691        //     if (!$counseling_flg) {
12692        //         $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12693        //         $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12694        //         $dailyNewsCampaignSettingId = Configure::read('campaign_config.daily_news.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12695
12696        //         $response['dailyNewsCampaignSettingId'] = $dailyNewsCampaignSettingId;
12697        //         $response['dailyNewsCampaign'] = $dailyNewsCampaign;
12698        //         $response['showDailyNewsCampModal'] = (!in_array($dailyNewsCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12699
12700        //         $cst = ClassRegistry::init('CampaignSettingTable');
12701        //         $campaignStamps = $cst->dailyNews(
12702        //             array(
12703        //                 'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12704        //                 'type' => 1
12705        //             )
12706        //         );
12707        //         $response['campaignStamps'] = $campaignStamps;
12708        //         $modalCampaignType = 'campaign_dailynews_live';
12709        //         $campaignTerm = $dailyNewsCampaign;
12710        //     }
12711        // }
12712
12713        if ($favoriteTeacherCampaign) {
12714            if (!$counseling_flg) {
12715                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12716                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12717                $favoriteTeacherCampaignSettingId = Configure::read('campaign_config.favorite_teacher.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12718
12719                $response['favoriteTeacherCampaignSettingId'] = $favoriteTeacherCampaignSettingId;
12720                $response['favoriteTeacherCampaign'] = $favoriteTeacherCampaign;
12721                $response['showFavoriteTeacherCampModal'] = (!in_array($favoriteTeacherCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12722
12723                $cst = ClassRegistry::init('CampaignSettingTable');
12724                $campaignStamps = $cst->favoriteTeacher(
12725                    array(
12726                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12727                        'type' => 1,
12728                        'requested_events' => array(1)
12729                    )
12730                );
12731                $response['campaignStamps'] = $campaignStamps['event1'];
12732                $modalCampaignType = 'campaign_favorite_teachers_live';
12733                $campaignTerm = $favoriteTeacherCampaign;
12734            }
12735        }
12736
12737        if ($familyPlanCampaign) {
12738            if (!$counseling_flg) {
12739                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12740                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12741                $familyPlanCampaignSettingId = Configure::read('campaign_config.family_plan.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12742
12743                $response['familyPlanCampaignSettingId'] = $familyPlanCampaignSettingId;
12744                $response['familyPlanCampaign'] = $familyPlanCampaign;
12745                $response['showFamilyPlanCampModal'] = (!in_array($familyPlanCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12746
12747                $cst = ClassRegistry::init('CampaignSettingTable');
12748                $lessonLogsFPC = $cst->familyPlan(
12749                    array(
12750                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12751                        'type' => 1
12752                    )
12753                );
12754                $response['lessonLogsFPC'] = $lessonLogsFPC;
12755                $modalCampaignType = 'campaign_plan_family_live';
12756                $campaignTerm = $familyPlanCampaign;
12757            }
12758        }
12759
12760        if ($christmasCampaign) {
12761            if (!$counseling_flg) {
12762                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12763                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12764                $christmasCampaignSettingId = Configure::read('campaign_config.christmas.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12765
12766                $response['christmasCampaignSettingId'] = $christmasCampaignSettingId;
12767                $response['christmasCampaign'] = $christmasCampaign;
12768                $response['showChristmasCampModal'] = (!in_array($christmasCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12769
12770                $cst = ClassRegistry::init('CampaignSettingTable');
12771                $lessonStamps = $cst->christmas(
12772                    array(
12773                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12774                        'type' => 1,
12775                    )
12776                );
12777                $response['lessonStamps'] = $lessonStamps;
12778                $modalCampaignType = 'campaign_christmas_live';
12779                $campaignTerm = $christmasCampaign;
12780            }
12781        }
12782
12783        if ($newYearPart1Campaign) {
12784            $campaignID = Configure::read('campaign_config.new_year_part_1.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_login');
12785            $lotteryData = array();
12786            $cst = ClassRegistry::init('CampaignSettingTable');
12787            $newYearLessonData = $cst->checkLastLesson(
12788                array(
12789                    'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12790                    'chat_hash' => $chat_hash,
12791                    'campaign_id' => $campaignID[0]
12792                )
12793            );
12794            $response['newYearPart1Campaign'] = $newYearPart1Campaign;
12795            $response['showNewYearPart1CampModal'] = ($newYearLessonData) ? true : false;
12796            $modalCampaignType = ($newYearLessonData) ? 'campaign_new_year_afterlesson' : '';
12797            $campaignTerm = $newYearPart1Campaign;
12798        }
12799
12800        if ($newGrammarCampaign) {
12801            if (!$counseling_flg) {
12802                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12803                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12804                $newGrammarCampaignSettingId = Configure::read('campaign_config.new_grammar.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12805    
12806                $response['newGrammarCampaignSettingId'] = $newGrammarCampaignSettingId;
12807                $response['newGrammarCampaign'] = $newGrammarCampaign;
12808                $response['showNewGrammarCampAfterLessonModal'] = (!in_array($newGrammarCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12809
12810                $cst = ClassRegistry::init('CampaignSettingTable');
12811                $campaignStamps = $cst->newGrammar(
12812                    array(
12813                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12814                        'type' => 1
12815                    )
12816                );
12817                $response['campaignStamps'] = $campaignStamps;
12818                $modalCampaignType = 'campaign_newgrammar_live';
12819                $campaignTerm = $newGrammarCampaign;
12820            }
12821        }
12822
12823        if ($alvarkCollab2Campaign) {
12824            if (!$counseling_flg) {
12825                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12826                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12827                $alvarkCollab2CampaignSettingId = Configure::read('campaign_config.alvark_collab_2.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12828    
12829                $response['alvarkCollab2CampaignSettingId'] = $alvarkCollab2CampaignSettingId;        
12830                $response['alvarkCollab2Campaign'] = $alvarkCollab2Campaign;
12831                $response['showAlvarkCollab2CampAfterLessonModal'] = (!in_array($alvarkCollab2CampaignSettingId, $dontShowCampaignModals)) ? true : false;    
12832
12833                $cst = ClassRegistry::init('CampaignSettingTable');
12834                $avk2coupon = $cst->alvarkCollab2(
12835                    array(
12836                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12837                        'type' => 1
12838                    )
12839                );
12840                $response['avk2coupon'] = $avk2coupon;
12841                $modalCampaignType = 'mypage_going_global_alvark_live';
12842                $campaignTerm = $alvarkCollab2Campaign;
12843            }
12844        }
12845
12846        if ($goldenWeekNCChallengeCampaign) {
12847            if (!$counseling_flg) {
12848                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12849                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12850                $campModalSettingIDs = Configure::read('campaign_config.golden_week_nc_challenge.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings');
12851                $goldenWeekNCChallengeCampaignSettingId = ($memberType == 'student') ? $campModalSettingIDs['after_lesson'] : $campModalSettingIDs['after_live_lesson_viewer'];
12852
12853                $cst = ClassRegistry::init('CampaignSettingTable');
12854                $check = $cst->checkGoldenWeekChallengeModals(array(
12855                    'user_id' => $userData->id,
12856                    'chat_hash' => $chat_hash,
12857                    'camp_setting_id' => $goldenWeekNCChallengeCampaignSettingId
12858                ));
12859
12860                //Get stamp
12861                $goldenWeekNCChallengeStamp = $cst->goldenWeekChallenge(
12862                    array(
12863                        'user_id' => $userData->id,
12864                        'type' => 1,
12865                        'challenge_stamp' => ($memberType == 'student') ? 3 : 2
12866                    )
12867                );
12868
12869                $displayModalAfterLesson = (!in_array($goldenWeekNCChallengeCampaignSettingId, $dontShowCampaignModals) && $check) ? true : false;
12870                
12871                $response['goldenWeekNCChallengeStamp'] = $goldenWeekNCChallengeStamp;
12872                $response['goldenWeekNCChallengeCampaignSettingId'] = $goldenWeekNCChallengeCampaignSettingId;
12873                $response['goldenWeekNCChallengeCampaignAfterLesson'] = $goldenWeekNCChallengeCampaign;
12874                $response['showGoldenWeekNCChallengeCampAfterLessonModal'] = $displayModalAfterLesson;
12875
12876                $modalCampaignType = ($memberType == 'student') ? 'campaign_golden_week_lesson' : 'campaign_golden_week_live';
12877                $modalCampaignType = ($displayModalAfterLesson) ? $modalCampaignType : '';
12878                $campaignTerm = $goldenWeekNCChallengeCampaign;
12879            }
12880        }
12881
12882
12883        //NJ-21995 Super native camp festival campaign
12884        $superNativeCamp = array(
12885            'campaign' => 'super_native_camp',
12886            'user_membership' => $userData->getMembershipTypeIndex()
12887        );
12888        if(!$counseling_flg && $campaignSetting->campaignChecker($superNativeCamp)){
12889            $campModalSettingIDs = Configure::read('campaign_config.super_native_camp.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings');
12890            $superNativeCampFestivalCampSettingID = $campModalSettingIDs['after_lesson'];
12891            $campaignTotalMinsOfLesson = $campaignSetting->superNativeCampFestival(array('user_id' => $userData->id, 'type' => 1));
12892            $checkCampaignLesson = $campaignSetting->superNativeCampFestival(array('user_id' => $userData->id, 'type' => 3, 'chat_hash' => $chat_hash));
12893            $displayModalAfterLesson = (!in_array($superNativeCampFestivalCampSettingID, $dontShowCampaignModals) && $checkCampaignLesson) ? true : false;;
12894            $response['campaignTotalMinsOfLesson'] = $campaignTotalMinsOfLesson;
12895            $response['superNativeCampFestivalCampSettingID'] = $superNativeCampFestivalCampSettingID;
12896            $response['showSuperNativeCampFestivalCampAfterLessonModal'] = $displayModalAfterLesson;
12897
12898            $modalCampaignType = 'campaign_nc_festival_live';
12899            $campaignTerm = true;
12900        }
12901
12902        //NJ-25217 Online English Conversation No.1 Festival
12903        $camp_OECF = array(
12904            'campaign' => 'OECF',
12905            'user_membership' => $userData->getMembershipTypeIndex(),
12906            'allow_language' => array(Configure::read('default.user_language'), 'en'),
12907            'user_language' => ($this->localizeDir == Configure::read('default.user_language') && in_array($userData->native_language2, array(Configure::read('default.user_language'), 'en'))) ? Configure::read('default.user_language') : $this->localizeDir,
12908            'user_currency' => $userData->currency_code,
12909            'allow_currency' => ($userData->native_language2 == 'en') ? array(Configure::read('default.user_currency')) : null
12910        );
12911        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_OECF)){
12912            $campModalSettingIDs = Configure::read('campaign_config.OECF.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings');
12913            $camp_OECF_setting_ID = $campModalSettingIDs['after_lesson'][0];
12914            $dataStamp = $campaignSetting->onlineEnglishConversationFestival(array('user_id' => $userData->id, 'type' => 1, 'device' => 1));
12915            $displayModalAfterLesson = (!in_array($camp_OECF_setting_ID, $dontShowCampaignModals)) ? true : false;
12916            $response['dataStamp'] = $dataStamp;
12917            $response['OECFCampSettingID'] = $camp_OECF_setting_ID;
12918            $response['showOECFCampAfterLessonModal'] = $displayModalAfterLesson;
12919
12920            $modalCampaignType = 'campaign_nc_no1_festival_live';
12921            $campaignTerm = true;
12922        }
12923
12924        // - NJ-31307 Callan Unlimited Campaign
12925        $camp_callan_unlimited = array(
12926            'campaign' => 'callan_unlimited',
12927            'user_membership' => $userData->getMembershipTypeIndex()
12928        );
12929        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_callan_unlimited)){
12930            $camp_callan_unlimited_ID = Configure::read('campaign_config.callan_unlimited.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12931            $displayModalAfterLesson = (!in_array($camp_callan_unlimited_ID, $dontShowCampaignModals)) ? true : false;
12932            if($displayModalAfterLesson){
12933                $modalCampaignType = 'campaign_callan_unlimited_afterlesson';
12934                $campaignTerm = true;
12935            }
12936        }
12937
12938        // - NJ-32989 : New Year Lottery Campaign
12939        $camp_new_year_lottery = array(
12940            'campaign' => 'new_year_lottery',
12941            'user_membership' => $userData->getMembershipTypeIndex(),
12942            'user_language' => $userData->native_language2,
12943            'allow_language' => Configure::read('campaign_config.new_year_lottery.allow_languages'),
12944            'user_currency' => $userData->currency_code,
12945            'other_validation' => true,
12946        );
12947        if($campaignSetting->campaignChecker($camp_new_year_lottery)){
12948            $camp_new_year_lottery_ID = Configure::read('campaign_config.new_year_lottery.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12949            $displayModalAfterLesson = (!in_array($camp_new_year_lottery_ID[0], $dontShowCampaignModals)) ? true : false;
12950            if($displayModalAfterLesson){
12951                $modalCampaignType = 'campaign_new_year_afterlesson';
12952                $campaignTerm = true;
12953            }
12954        }
12955
12956        // - NJ-32989 Around the world campaign
12957        $camp_around_the_world = array(
12958            'campaign' => 'around_the_world',
12959            'user_membership' => $userData->getMembershipTypeIndex(),
12960            'user_currency' => $userData->currency_code,
12961            'allow_currency' => Configure::read('campaign_config.around_the_world.allow_currencies'),
12962            'user_language' => $userData->native_language2,
12963            'allow_language' => Configure::read('campaign_config.around_the_world.allow_languages'),
12964        );
12965        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_around_the_world)){
12966            $camp_around_the_world_ID = Configure::read('campaign_config.around_the_world.modal_settings.after_lesson');
12967            $displayModalAfterLesson = (!in_array($camp_around_the_world_ID, $dontShowCampaignModals)) ? true : false;
12968            if($displayModalAfterLesson){
12969                $modalCampaignType = 'campaign_around_the_world_afterlesson';
12970                $campaignTerm = true;
12971            }
12972        }
12973
12974        // - NJ-36818 : What are you doing now? Native Camp! Campaign
12975        $camp_spare_time = array(
12976            'campaign' => 'spare_time_march',
12977            'user_membership' => $userData->getMembershipTypeIndex(),
12978            'user_language' => $userData->native_language2,
12979            'allow_language' => Configure::read('campaign_config.spare_time_march.allow_languages'),
12980        );
12981        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_spare_time)){
12982            $camp_spare_time_ID = Configure::read('campaign_config.spare_time_march.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12983            $displayModalAfterLesson = (!in_array($camp_spare_time_ID, $dontShowCampaignModals)) ? true : false;
12984            if($displayModalAfterLesson){
12985                $modalCampaignType = 'campaign_spare_time_afterlesson';
12986                $campaignTerm = true;
12987            }
12988        }
12989
12990        // - NJ-39740 : 1.5 Million - Thank You Campaign
12991        $camp_opfm = array(
12992            'campaign' => 'OPFM_campaign',
12993            'user_membership' => $userData->getMembershipTypeIndex(),
12994            'user_language' => $userData->native_language2,
12995            'allow_language' => Configure::read('campaign_config.OPFM_campaign.allow_languages'),
12996        );
12997        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_opfm)){
12998            $camp_opfm_ID = Configure::read('campaign_config.OPFM_campaign.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12999            $displayModalAfterLesson = (!in_array($camp_opfm_ID, $dontShowCampaignModals)) ? true : false;
13000            if($displayModalAfterLesson){
13001                $modalCampaignType = 'campaign_150_ten_thousand_afterlesson';
13002                $campaignTerm = true;
13003            }
13004        }
13005
13006        // - NJ-42488 : kakaku_01 campaign
13007        $camp_kakaku01 = array(
13008            'campaign' => 'kakaku_01',
13009            'user_membership' => $userData->getMembershipTypeIndex(),
13010        );
13011        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_kakaku01)){
13012            $camp_kakaku_01_IDs = Configure::read('campaign_config.kakaku_01.modal_settings.after_lesson');
13013            if($userData->native_language2 == Configure::read('default.user_language')){
13014                $displayModalAfterLesson = (!in_array($camp_kakaku_01_IDs[0], $dontShowCampaignModals)) ? true : false;
13015                if($displayModalAfterLesson){
13016                    $modalCampaignType = 'campaign_kakaku_01_live';
13017                    $campaignTerm = true;
13018                }
13019            } else {
13020                $displayModalAfterLesson = (!in_array($camp_kakaku_01_IDs[1], $dontShowCampaignModals)) ? true : false;
13021                if($displayModalAfterLesson){
13022                    $modalCampaignType = 'campaign_dailynews_live';
13023                    $campaignTerm = true;
13024                }
13025            }
13026        }
13027
13028        // - NJ-45886 [Campaign] AI Speaking Campaign
13029        $camp_ai_speaking_sept = array(
13030            'campaign' => 'ai_speaking_sept',
13031            'user_membership' => $userData->getMembershipTypeIndex(),
13032            'user_language' => $userData->native_language2,
13033            'allow_language' => Configure::read('campaign_config.ai_speaking_sept.allow_languages'),
13034        );
13035        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_ai_speaking_sept)){
13036            $camp_ai_speaking_sept_IDs = Configure::read('campaign_config.ai_speaking_sept.modal_settings.after_lesson');
13037            $displayModalAfterLesson = (!in_array($camp_ai_speaking_sept_IDs[0], $dontShowCampaignModals)) ? true : false;
13038            if($displayModalAfterLesson){
13039                $modalCampaignType = 'campaign_speaking_afterlesson';
13040                $campaignTerm = true;
13041            }
13042        }
13043
13044        //NJ-50048 Lesson coin gift campaign
13045        $lessonCoinGiftCamp = array(
13046            'campaign' => 'taking_lesson_and_continue_plan',
13047            'user_membership' => $userData->getMembershipTypeIndex(),
13048            'allow_language' => Configure::read('campaign_config.taking_lesson_and_continue_plan.allowed_languages'),
13049            'user_language' => $userData->native_language2,
13050        );
13051        if(!$counseling_flg && $campaignSetting->campaignChecker($lessonCoinGiftCamp)){
13052            $campModalSettingIDs = Configure::read('campaign_config.taking_lesson_and_continue_plan.modal_settings');
13053            $lessonCoinGiftCampSettingID = $campModalSettingIDs['after_lesson'];
13054            $displayModalAfterLesson = (!in_array($lessonCoinGiftCampSettingID, $dontShowCampaignModals)) ? true : false;
13055            if($displayModalAfterLesson){
13056                $modalCampaignType = 'campaign_lesson_coin_gift_live';
13057                $campaignTerm = true;
13058            }
13059        }
13060
13061        //NJ-55569 2025 New Year Campaign
13062        $newYearCamp = array(
13063            'campaign' => 'newyear_2025',
13064            'user_membership' => $userData->getMembershipTypeIndex(),
13065            'allow_language' => Configure::read('campaign_config.newyear_2025.allowed_languages'),
13066            'user_language' => $userData->native_language2,
13067            'allow_currency' => Configure::read('campaign_config.newyear_2025.allowed_currencies'),
13068            'user_currency' => $userData->currency_code,
13069        );
13070        if(!$counseling_flg && $campaignSetting->campaignChecker($newYearCamp)){
13071            $campModalSettingIDs = Configure::read('campaign_config.newyear_2025.modal_settings');
13072            $newYearCampSettingID = $campModalSettingIDs['after_lesson'];
13073            if($userData->native_language2 == Configure::read('default.user_language')){
13074                $displayModalAfterLesson = (!in_array($newYearCampSettingID[0], $dontShowCampaignModals)) ? true : false;
13075                if($displayModalAfterLesson){
13076                    $modalCampaignType = 'campaign_new_year_live';
13077                    $campaignTerm = true;
13078                }
13079            } else {
13080                $displayModalAfterLesson = (!in_array($newYearCampSettingID[1], $dontShowCampaignModals)) ? true : false;
13081                if($displayModalAfterLesson){
13082                    $modalCampaignType = 'campaign_dailynews_live';
13083                    $campaignTerm = true;
13084                }
13085            }
13086        }
13087
13088        //NJ-59889 3 Million Campaign
13089        $threeMillionCamp = array(
13090            'campaign' => '3_million',
13091            'user_membership' => $userData->getMembershipTypeIndex(),
13092            'allow_language' => Configure::read('campaign_config.3_million.allowed_languages'),
13093            'user_language' => $userData->native_language2,
13094            'allow_currency' => Configure::read('campaign_config.3_million.allowed_currencies'),
13095            'user_currency' => $userData->currency_code,
13096        );
13097        if(!$counseling_flg && $campaignSetting->campaignChecker($threeMillionCamp)){
13098            $threeMillionCampSettingId = Configure::read('campaign_config.3_million.modal_settings.after_lesson');
13099            $displayModalAfterLesson = (!in_array($threeMillionCampSettingId, $dontShowCampaignModals)) ? true : false;
13100            if($displayModalAfterLesson){
13101                $modalCampaignType = 'campaign_3_million_afterlesson';
13102                $campaignTerm = true;
13103            }
13104        }
13105
13106        // - NJ-65066 【Campaign】Daily Topics
13107        $dailytopicsCamp = array(
13108            'campaign' => 'daily_topics',
13109            'user_membership' => $userData->getMembershipTypeIndex(),
13110            'allow_language' => Configure::read('campaign_config.daily_topics.allowed_languages'),
13111            'user_language' => $userData->native_language2,
13112            'allow_currency' => Configure::read('campaign_config.daily_topics.allowed_currencies'),
13113            'user_currency' => $userData->currency_code,
13114        );
13115        if(!$counseling_flg && $campaignSetting->campaignChecker($dailytopicsCamp)){
13116            $dailytopicsCampSettingId = Configure::read('campaign_config.daily_topics.modal_settings.after_lesson');
13117            $displayModalAfterLesson = (!in_array($dailytopicsCampSettingId, $dontShowCampaignModals)) ? true : false;
13118            if($displayModalAfterLesson){
13119                $modalCampaignType = 'campaign_dailytopics_afterlesson';
13120                $campaignTerm = true;
13121            }
13122        }
13123
13124        $response['campaign_name'] = $modalCampaignType;
13125        $response['campaignPageRecord'] = $campaignPageRecord;
13126        $response['campaignTerm'] = $campaignTerm;
13127
13128        return $response;
13129    }
13130
13131
13132    //Retrieves the active campaign stamp data for the authenticated user in Native Camp. It checks various campaigns and sets the campaign data for the view.
13133    public function getActiveCampaignStampData($params = []) {
13134
13135        $usrObj = new UserTable($this->sharedUserData['User']);
13136        $cst_ = ClassRegistry::init('CampaignSettingTable');
13137
13138        // - NJ-31307 Callan unlimited campaign
13139        $camp_callan_unlimited = array(
13140            'campaign' => 'callan_unlimited',
13141            'user_membership' => $usrObj->getMembershipTypeIndex()
13142        );
13143        if($cst_->campaignChecker($camp_callan_unlimited)){
13144            $campaignStamp = $cst_->callanUnlimitedCampaign(array(
13145                'trigger' => 1,
13146                'user_id' => $usrObj->id
13147            ));
13148            $camp_callan_unlimited_ID = Configure::read('campaign_config.callan_unlimited.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13149            $this->set('campaignStamp', $campaignStamp);
13150            $this->set('callanUnlimitedSettingID', $camp_callan_unlimited_ID);
13151            $this->set('showCallanUnlimitedAfterLessonModal', true);
13152        }
13153
13154        // - NJ-32989 : New Year Lottery Campaign
13155        $camp_new_year_lottery = array(
13156            'campaign' => 'new_year_lottery',
13157            'user_membership' => $usrObj->getMembershipTypeIndex(),
13158            'user_language' => $usrObj->native_language2,
13159            'allow_language' => Configure::read('campaign_config.new_year_lottery.allow_languages'),
13160            'user_currency' => $usrObj->currency_code,
13161            'other_validation' => true,
13162        );
13163        if($cst_->campaignChecker($camp_new_year_lottery)){
13164            $campaignLotteryTicket = $cst_->newYearLotteryCamp(array(
13165                'trigger' => 1,
13166                'user_id' => $usrObj->id
13167            ));
13168            $camp_new_year_lottery_ID = Configure::read('campaign_config.new_year_lottery.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13169            $this->set('campaignLotteryTicket', $campaignLotteryTicket);
13170            $this->set('newYearLotterySettingID', $camp_new_year_lottery_ID[0]);
13171            $this->set('showNewYearLotteryAfterLessonModal', true);
13172        }
13173
13174        // - NJ-32989 Around the world campaign
13175        $camp_around_the_world = array(
13176            'campaign' => 'around_the_world',
13177            'user_membership' => $usrObj->getMembershipTypeIndex(),
13178            'user_currency' => $usrObj->currency_code,
13179            'allow_currency' => Configure::read('campaign_config.around_the_world.allow_currencies'),
13180            'user_language' => $usrObj->native_language2,
13181            'allow_language' => Configure::read('campaign_config.around_the_world.allow_languages'),
13182
13183        );
13184        if($cst_->campaignChecker($camp_around_the_world)){
13185            $stampData = ClassRegistry::init('CampaignSettingTable')->aroundTheWorldCamp(['user_id' => $usrObj->id, 'trigger' => 1]);
13186            $camp_around_the_world_ID = Configure::read('campaign_config.around_the_world.modal_settings.after_lesson');
13187            $this->set('aroundTheWorldSettingID', $camp_around_the_world_ID);
13188            $this->set('showAroundTheWorldAfterLessonModal', true);
13189            $this->set('total_stamp_count', $stampData['total_count'] ?? 0 );
13190            $this->set('stamp_html', $stampData['stamp_html'] ?? '' );
13191        }
13192
13193        // - NJ-36818 : What are you doing now? Native Camp! Campaign
13194        $camp_spare_time = array(
13195            'campaign' => 'spare_time_march',
13196            'user_membership' => $usrObj->getMembershipTypeIndex(),
13197            'user_language' => $usrObj->native_language2,
13198            'allow_language' => Configure::read('campaign_config.spare_time_march.allow_languages'),
13199        );
13200        if($cst_->campaignChecker($camp_spare_time)){
13201            $campaignStamp = $cst_->spareTimeCampaign(array(
13202                'trigger' => 1,
13203                'user_id' => $usrObj->id
13204            ));
13205            $camp_spare_time_ID = Configure::read('campaign_config.spare_time_march.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13206            $this->set('spareTimeCampaignStamp', $campaignStamp);
13207            $this->set('spareTimeSettingID', $camp_spare_time_ID);
13208            $this->set('showSpareTimeAfterLessonModal', true);
13209        }
13210
13211        // 1.5 Million - Thank You Campaign
13212        $camp_opfm = array(
13213            'campaign' => 'OPFM_campaign',
13214            'user_membership' => $usrObj->getMembershipTypeIndex(),
13215            'user_language' => $usrObj->native_language2,
13216            'allow_language' => Configure::read('campaign_config.OPFM_campaign.allow_languages'),
13217        );
13218        if($cst_->campaignChecker($camp_opfm)){
13219            $campaignStamp = $cst_->opfmCampaign(array(
13220                'trigger' => 1,
13221                'user_id' => $usrObj->id
13222            ));
13223            $camp_opfm_ID = Configure::read('campaign_config.OPFM_campaign.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13224            $this->set('opfmCampaignStamp', $campaignStamp);
13225            $this->set('opfmSettingID', $camp_opfm_ID);
13226            $this->set('showOpfmAfterLessonModal', true);
13227        }
13228
13229        // - NJ-42488 : kakaku_01 campaign
13230        $camp_kakaku01 = array(
13231            'campaign' => 'kakaku_01',
13232            'user_membership' => $usrObj->getMembershipTypeIndex()
13233        );
13234        if($cst_->campaignChecker($camp_kakaku01)){
13235            $kakakuCampaignStamp = ClassRegistry::init('CampaignSettingTable')->kakaku01_camp(array(
13236                'trigger' => 1,
13237                'user_id' => ($this->Auth->loggedIn()) ? $usrObj->id : null,
13238            ));
13239            $camp_kakaku_01_IDs = Configure::read('campaign_config.kakaku_01.modal_settings.after_lesson');
13240            if( $usrObj->native_language2 == Configure::read('default.user_language')){
13241                $this->set('kakakuCampaignStamp', $kakakuCampaignStamp);
13242                $this->set('kakaku01SettingID', $camp_kakaku_01_IDs[0]);
13243                $this->set('showKakaku01AfterLessonModal', true);
13244            } else {
13245                $this->set('kakakuCampaignStamp', $kakakuCampaignStamp);
13246                $this->set('kakaku01SettingID', $camp_kakaku_01_IDs[1]);
13247                $this->set('showKakaku01DailyNewsAfterLessonModal', true);
13248            }
13249        }
13250
13251        // - NJ-42488 : kakaku_01 campaign
13252        $camp_ai_speaking_sept = array(
13253            'campaign' => 'ai_speaking_sept',
13254            'user_membership' => $usrObj->getMembershipTypeIndex(),
13255            'user_language' => $usrObj->native_language2,
13256            'allow_language' => Configure::read('campaign_config.ai_speaking_sept.allow_languages')
13257        );
13258        if($cst_->campaignChecker($camp_ai_speaking_sept)){
13259            $aiSpeakingSeptCampaignStamp = ClassRegistry::init('CampaignSettingTable')->ai_speaking_camp(array(
13260                'trigger' => 1,
13261                'user_id' => ($this->Auth->loggedIn()) ? $usrObj->id : null,
13262            ));
13263            $camp_ai_speaking_sept_IDs = Configure::read('campaign_config.ai_speaking_sept.modal_settings.after_lesson');
13264            $this->set('aiSpeakingSeptCampaignStamp', $aiSpeakingSeptCampaignStamp);
13265            $this->set('aiSpeakingSeptSettingID', $camp_ai_speaking_sept_IDs[0]);
13266            $this->set('showAISpeakingSeptAfterLessonModal', true);
13267        }
13268
13269        //NJ-50048 Lesson coin gift campaign
13270        $lessonCoinGiftCamp = array(
13271            'campaign' => 'taking_lesson_and_continue_plan',
13272            'user_membership' => $usrObj->getMembershipTypeIndex(),
13273            'allow_language' => Configure::read('campaign_config.taking_lesson_and_continue_plan.allowed_languages'),
13274            'user_language' => $usrObj->native_language2,
13275        );
13276        if($cst_->campaignChecker($lessonCoinGiftCamp)){
13277            $campModalSettingIDs = Configure::read('campaign_config.taking_lesson_and_continue_plan.modal_settings');
13278            $lessonCoinGiftCampSettingID = $campModalSettingIDs['after_lesson'];
13279            $dataStamp = $cst_->takingLessonAndContinuePlan(array('user_id' => $usrObj->id, 'type' => 1, 'device' => 1));
13280            $this->set('dataStamp', $dataStamp);
13281            $this->set('lessonCoinGiftCampSettingID', $lessonCoinGiftCampSettingID);
13282            $this->set('showLessonCoinGiftCampAfterLessonModal', true);
13283        }
13284
13285        //NJ-55569 2025 New Year Campaign
13286        $newYearCamp = array(
13287            'campaign' => 'newyear_2025',
13288            'user_membership' => $usrObj->getMembershipTypeIndex(),
13289            'allow_language' => Configure::read('campaign_config.newyear_2025.allowed_languages'),
13290            'user_language' => $usrObj->native_language2,
13291            'allow_currency' => Configure::read('campaign_config.newyear_2025.allowed_currencies'),
13292            'user_currency' => $usrObj->currency_code,
13293        );
13294        if($cst_->campaignChecker($newYearCamp)){
13295            $campModalSettingIDs = Configure::read('campaign_config.newyear_2025.modal_settings');
13296            $newYearCampSettingID = $campModalSettingIDs['after_lesson'];
13297            $newyear2025_stamp = $cst_->newyear2025_camp(array('user_id' => $usrObj->id, 'trigger' => 1));
13298            $this->set('newyear2025_stamp', $newyear2025_stamp);
13299
13300            if( $usrObj->native_language2 == Configure::read('default.user_language')){
13301                $this->set('showNewYearCampAfterLessonModal', true);
13302                $this->set('newYearCampSettingID', $newYearCampSettingID[0]);
13303            } else {
13304                $this->set('showNewYearDailyNewsCampAfterLessonModal', true);
13305                $this->set('newYearCampSettingID', $newYearCampSettingID[1]);
13306            }
13307        }
13308
13309        //NJ-59889 3 Million Campaign
13310        $threeMillionCamp = array(
13311            'campaign' => '3_million',
13312            'user_membership' => $usrObj->getMembershipTypeIndex(),
13313            'allow_language' => Configure::read('campaign_config.3_million.allowed_languages'),
13314            'user_language' => $usrObj->native_language2,
13315            'allow_currency' => Configure::read('campaign_config.3_million.allowed_currencies'),
13316            'user_currency' => $usrObj->currency_code,
13317        );
13318        if($cst_->campaignChecker($threeMillionCamp)){
13319            $threeMillionCampSettingId = Configure::read('campaign_config.3_million.modal_settings.after_lesson');
13320            $campaignStamp = $cst_->threeMillionCamp([
13321                'trigger' => 1,
13322                'user_id' => $usrObj->id,
13323                'lang' => $this->localizeDir
13324            ]);
13325            $this->set( 'threeMillionCampaignStamp', $campaignStamp );
13326            $this->set('showthreeMillionCampAfterLessonModal', true);
13327            $this->set('threeMillionCampSettingId', $threeMillionCampSettingId);
13328        }
13329
13330        // - NJ-65066 【Campaign】Daily Topics
13331        $dailytopicsCamp = array(
13332            'campaign' => 'daily_topics',
13333            'user_membership' => $usrObj->getMembershipTypeIndex(),
13334            'allow_language' => Configure::read('campaign_config.daily_topics.allowed_languages'),
13335            'user_language' => $usrObj->native_language2,
13336            'allow_currency' => Configure::read('campaign_config.daily_topics.allowed_currencies'),
13337            'user_currency' => $usrObj->currency_code,
13338        );
13339        if($cst_->campaignChecker($dailytopicsCamp)){
13340            $dailytopicsCampSettingId = Configure::read('campaign_config.daily_topics.modal_settings.after_lesson');
13341            $campaignStamp = $cst_->dailyTopics([
13342                'trigger' => 1,
13343                'user_id' => $usrObj->id,
13344                'lang' => $this->localizeDir
13345            ]);
13346            $this->set( 'dailytopicsCampaignStamp', $campaignStamp );
13347            $this->set('showdailytopicsCampAfterLessonModal', true);
13348            $this->set('dailytopicsCampSettingId', $dailytopicsCampSettingId);
13349        }
13350        
13351        $this->set('userToken', $this->Auth->user('api_token'));
13352    }
13353
13354
13355    //Determines whether to show the campaign modal based on the current date and the provided start and end dates.
13356    public function showCampaignModal($startDate = null, $endDate = null){
13357        if(!empty($startDate) && !empty($endDate)){
13358            $current_date = strtotime('now');
13359            $showCampaignModal = $current_date >= strtotime($startDate) && $current_date <= strtotime($endDate) ? true : false;
13360
13361            return $showCampaignModal;
13362        }
13363
13364        return false;
13365    }
13366
13367    /**
13368     * @api {post} /user/waiting/generateTextbookTeacherRecommendAjax generateTextbookTeacherRecommendAjax()
13369     * @apiName generateTextbookTeacherRecommendAjax
13370     * @apiGroup Waiting
13371     * @apiDescription Generates a list of recommended teachers for a specific textbook in Native Camp. It retrieves the teacher recommendations based on the user's last lesson and textbook data.
13372     *
13373     * @apiBody {String} category_id The ID of the textbook category.
13374     * @apiBody {String} connect_id The ID of the textbook connect.
13375     * @apiBody {String} teacher_id The ID of the teacher.
13376     * 
13377     * @apiSuccess {Number} result Indicates whether the operation was successful.
13378     * @apiSuccess {String} html The HTML content for the recommended teachers modal.
13379     *
13380     * @apiSuccessExample {json} Success-Response:
13381     *     {
13382     *         "result": 1,
13383     *         "html": "<div>Recommended Teachers</div>"
13384     *     }
13385     *
13386     * @apiError {Number} result Indicates whether the operation was successful.
13387     * @apiError {String} html The HTML content for the recommended teachers modal.
13388     *
13389     * @apiErrorExample {json} Error-Response:
13390     *     {
13391     *         "result": 0,
13392     *         "html": ""
13393     *     }
13394     * 
13395     * @apiSampleRequest off
13396     */
13397    public function generateTextbookTeacherRecommendAjax() {
13398        $this->autoRender = false;
13399        $this->layout = false;
13400        $resultSuccess = 0;
13401        $resultHTML = '';
13402        $isSubmittedFiveStar = 0;
13403        if ($this->request->is('ajax')) {
13404
13405            $curDate = date('Y-m-d');
13406            $userId = $this->Auth->user('id') ? $this->Auth->user('id') : null;
13407            $txtTeacherRecommendlimit = 3; // modal limit
13408            $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
13409            $endDate = date('Y-m-d',strtotime('-1 day' ,strtotime($curDate)));
13410            $beginDate = date('Y-m-d',strtotime('-1 month' ,strtotime($curDate)));
13411            $categoryId = isset($this->request->data['category_id']) ? $this->request->data['category_id'] : null;
13412            $connectId = isset($this->request->data['connect_id']) ? $this->request->data['connect_id'] : null;
13413            $teacherId = isset($this->request->data['teacher_id']) ? $this->request->data['teacher_id'] : null;
13414            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : null;
13415
13416            if( $userId ) {
13417
13418
13419                // - NJ-8416: check for last lesson type
13420                $lastLessonType = ClassRegistry::init('LessonOnair')->getLastLessonType($userId);
13421                $this->log('[NJ-8416 lastLessonType lessonFinish] -> ' . json_encode($lastLessonType), 'debug');
13422                $lastBookUsedData = $this->UsersTextbookInfo->getCurrentTextbookAndBadgeData( array( 
13423                        'user_id' => $userId,
13424                        'connect_id' => $connectId,
13425                        'limit' => 3, // modal
13426                        'last_lesson_type' => $lastLessonType
13427                    ) 
13428                );
13429
13430                $textbookCategoryId = $lastBookUsedData['category_id'] ?? null;
13431                $textbookBadge = $lastBookUsedData['textbook_badge'] ?? null;
13432                $this->log('[NJ-8416 textbookCategoryId lessonFinish] -> ' . json_encode($textbookCategoryId), 'debug');
13433                $paramsArr = array(
13434                    'user_id' => $userId,
13435                    'begin_date' => $beginDate,
13436                    'end_date' => $endDate,
13437                    'textbook_category' => $textbookCategoryId,
13438                    'textbook_badge' => $textbookBadge,
13439                    'limit' => $txtTeacherRecommendlimit,
13440                    'user_data' => $userData,
13441                    'exclude_teacher_id' => $teacherId
13442                );
13443
13444                $teacherTextbookStatData = $this->TeacherTextbookStat->fetchTextbookTeacherRatingData($paramsArr);
13445                if( $teacherTextbookStatData ) {
13446                    $dataList = $this->arrangeTeacherRecommendList( array( 
13447                            'user_id' => $userId,
13448                            'data' => $teacherTextbookStatData,
13449                            'category_id' => $textbookCategoryId,
13450                            'user_data' => $userData
13451                        )
13452                    );
13453
13454                    $this->set('textbookTeacherData', $dataList);
13455                    $view = new View($this, false);
13456                    $resultHTML = $view->element( 'lesson_finish_textbook_teacher_list_modal', array(
13457                            'textbookTeacherData' => isset($dataList) && $dataList ? $dataList : array()
13458                        )
13459                    );
13460                    $resultSuccess = 1;
13461                }
13462
13463                //- NJ-61019: get rating from mecached
13464                if($chatHash && $chatHash != 'hash') {
13465                    if (!class_exists('myMemcached')) {
13466                        App::uses('myMemcached', 'Lib');
13467                    }
13468                    $memcached = new myMemcached();
13469                    $rate = $memcached->get("rating_".$chatHash);
13470
13471                    if(isset($rate) && $rate == 5) {
13472                        $isSubmittedFiveStar = 1;
13473                    }
13474                }
13475            }
13476
13477        }
13478        return json_encode(array(
13479            'result' => $resultSuccess,
13480            'html' => $resultHTML,
13481            'isSubmittedFiveStar' => $isSubmittedFiveStar
13482        ));
13483    }
13484
13485    /**
13486    * Ajax Request : fetch user's appreciation options data for modal display
13487    */
13488    //not used function
13489    public function setUpAppreciationSelectionModalElementAjax() {
13490        $this->autoRender = false;
13491        $this->layout = false;
13492        $result = array();
13493        if ($this->request->is('ajax')) {
13494            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : null;
13495            if($chatHash){
13496                $fetchParam = array( 'chat_hash'  => $chatHash );
13497                $fetchedData = $this->setUpAppreciationSelectionModalElement($fetchParam);
13498                if( isset( $fetchedData['html_element'] ) && $fetchedData['html_element'] ){
13499                    $result['html_element'] = $fetchedData['html_element'];
13500                }
13501            }
13502        }
13503        return json_encode(array(
13504            'result' => $result
13505        ));
13506    }
13507
13508    /**
13509    * Ajax Request : Send teacher's appreciation
13510    */
13511    //not used function
13512    public function sendTeacherAppreciationAjax() {
13513        $this->autoRender = false;
13514        $this->layout = false;
13515        $result = array( 'result' => 0 );
13516        $teacherAppreciationMessage = "";
13517        $teacherAppreciationAmount = 0;
13518        $hasTips = 1;
13519        $hasMessage = 1;
13520        $noMessageText = '';
13521        $noTipsText = '';
13522
13523        if ($this->request->is('ajax')) {
13524            $appreciationId = isset($this->request->data['appreciation_ration_input']) ? $this->request->data['appreciation_ration_input'] : null;
13525            $message = isset($this->request->data['user_comment_text']) ? trim($this->request->data['user_comment_text']) : null;
13526            $chatHash = isset($this->request->data['chat_hash_input']) ? $this->request->data['chat_hash_input'] : null;
13527            $actionMode = isset($this->request->data['action_mode']) ? $this->request->data['action_mode'] : 0;
13528            
13529            // - initialize api tunnel
13530            myTools::initializeApiTunnel(array('AppreciationController'));    
13531            $params = array(
13532                "users_api_token" => $this->Auth->user('api_token'),
13533                'chat_hash' => $chatHash,
13534                'appreciation_id'  => $appreciationId,
13535                'message' => $message,
13536                'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
13537
13538            );
13539            $api = new AppreciationController();
13540            $api->params = $params;
13541            
13542            // - send teacher appreciation
13543            $sendData = $api->send();
13544
13545            // - Detect prohibited words in teacher appreciation messages sent after class.
13546            $this->ProhibitedWord->detectProhibitedWordOnStudentAppreciation([
13547                'chat_hash' => $chatHash,
13548                'message' => $message,
13549            ]);
13550            
13551            if ( isset ($sendData['result'] ) && $sendData['result'] ) {
13552                // set default res
13553                $result = array( 'result' => 1 );
13554
13555                // set return appreciation item
13556                $appreciationDetails = $sendData['appreciation_item'];
13557
13558            } else {
13559                if( isset ($sendData['error'] ) && $sendData['error'] ){
13560                    $result['error']['id'] = 'sending_failed';
13561                    $result['error']['message'] = json_encode($sendData['error']);
13562                }
13563            }
13564
13565            // set appreciation details student message
13566            if(empty($appreciationDetails['student_message'])){
13567                $appreciationDetails['student_message'] = __d('modal','このお礼にメッセージはありません。');
13568                $appreciationDetails['student_message_flg'] = false;
13569            }else{
13570                $appreciationDetails['student_message_flg'] = true;
13571            }
13572
13573            if ( isset ($sendData['result'] ) && $sendData['result'] ) {
13574                $teacherAppreciationMessage = $appreciationDetails['message'];
13575                $teacherAppreciationAmount = $appreciationDetails['amount'];
13576
13577                if(empty($appreciationId)) {
13578                    // no apprecation tips form
13579                    $hasTips = 0;
13580                    if($appreciationId != 0)  {
13581                        $hasTips = 0;
13582                    }
13583                    $noTipsText = __d('modal','チップはありません');
13584                }
13585
13586                if (empty($message)) {
13587                    // no appreciation message form
13588                    $hasMessage = 0;
13589                    $noMessageText = __d('modal','メッセージはありません');
13590                }
13591
13592                $result = array( 'result' => 1 );
13593
13594                if ($actionMode == 1) {
13595                    $hasTips = 1;
13596                    $hasMessage = 1;
13597                }
13598
13599            } else {
13600                if( isset ($sendData['error'] ) && $sendData['error'] ){
13601                    $result['error']['id'] = 'sending_failed';
13602                    $result['error']['message'] = json_encode($sendData['error']);
13603                    if(isset($sendData['error']['error_code'])) {
13604                        $result['error']['error_code'] = json_encode($sendData['error']['error_code']);
13605                    }
13606                }
13607            }    
13608
13609        }
13610        return json_encode(array(
13611            'output' => $result,
13612            'appreciation_message' => $teacherAppreciationMessage,
13613            'appreciation_amount' => $teacherAppreciationAmount,
13614            'has_tips' => $hasTips,
13615            'has_message' => $hasMessage,
13616            'appreciation_details' => $appreciationDetails ?? [],
13617            'no_message_text' => $noMessageText,
13618            'no_tips_text' => $noTipsText
13619        ));
13620    }
13621
13622
13623    /**
13624    * ajax set after lesson evaluate system problem
13625    */
13626    //not used function
13627    public function ajaxUpdateSystemTrouble() {
13628        $this->autoRender = false;
13629        $this->layout = false;
13630        $troubleResponse = false;
13631        if ($this->request->is('ajax')) {
13632            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : '';
13633            $status = isset($this->request->data['value']) ? $this->request->data['value'] : 0;
13634            $lesson = $this->LessonOnairsLog->findByChatHash($chatHash, array('LessonOnairsLog.id'),null, -1);
13635            if (isset($lesson) && $lesson) {
13636                if (isset($lesson['LessonOnairsLog']['id']) && $lesson['LessonOnairsLog']['id']) {
13637                    if($this->LessonOnairsLog->read(null, $lesson['LessonOnairsLog']['id'])){
13638                        $this->LessonOnairsLog->saveField('lesson_system_trouble', $status);
13639                    }
13640                    $troubleResponse = true;
13641                }
13642            } 
13643        }
13644        return json_encode(array(
13645            'result' => $troubleResponse
13646        ));
13647    }
13648
13649    /**
13650     * @api {post} /user/waiting/reportProblem reportProblem()
13651     * @apiName reportProblem
13652     * @apiGroup Waiting
13653     * @apiDescription Reports a problem during a lesson in Native Camp. It updates the lesson status and sends a notification to Slack.
13654     *
13655     * @apiBody {String} problem The description of the problem.
13656     * @apiBody {String} chatHash The chat hash of the lesson.
13657     * @apiBody {String} [member_type] The type of the member (viewer or student).
13658     * 
13659     * @apiSuccess {Boolean} success Indicates whether the operation was successful.
13660     *
13661     * @apiSuccessExample {json} Success-Response:
13662     *     {
13663     *         "success": true
13664     *     }
13665     *
13666     * @apiError {Boolean} success Indicates whether the operation was successful.
13667     *
13668     * @apiErrorExample {json} Error-Response:
13669     *     {
13670     *         "success": false
13671     *     }
13672     * 
13673     * @apiSampleRequest off
13674     */
13675    public function reportProblem() {
13676        $this->autoRender = false;
13677        $this->layout = false;
13678
13679        if ($this->Auth->loggedIn() && isset($this->request->data['problem']) && isset($this->request->data['chatHash'])) {
13680            //get data
13681            $problem = $this->request->data['problem'];
13682            $chatHash = $this->request->data['chatHash'];
13683            $userId = $this->Auth->user('id');
13684            $memberType = isset($this->request->data['member_type']) ? $this->request->data['member_type'] : 'student';
13685
13686            if ($memberType == 'viewer') {
13687                //-live_system_trouble
13688                $res = $this->LessonOnairsViewer->updateAll(
13689                    array(
13690                        'LessonOnairsViewer.live_system_trouble' => 1
13691                    ),
13692                    array(
13693                        'LessonOnairsViewer.user_id' => $userId,
13694                        'LessonOnairsViewer.chat_hash' => $chatHash
13695                    )
13696                );
13697                return json_encode(array('success' => ($res?true:false)));
13698            }
13699
13700            $lessonData = LessonOnairTable::findLessonData(array(
13701                'fields' => array(
13702                    'id',
13703                    'teacher_id',
13704                    'user_id',
13705                    'chat_hash',
13706                    'lesson_system_trouble',
13707                    'user_agent'
13708                ),
13709                'conditions' => array(
13710                    'chat_hash' => $chatHash,
13711                    'user_id' => $userId
13712                )
13713            ));
13714
13715            //if no lesson data found
13716            if (!$lessonData) {
13717                return json_encode(array('success' => false));
13718            } elseif ($lessonData['data']['lesson_system_trouble'] == 0) {
13719                //update trouble
13720                $model = ClassRegistry::init($lessonData['model']);
13721                if ($model->read(null, $lessonData['data']['id'])) {
13722                    $model->set('lesson_system_trouble', 1);
13723                    $model->save();
13724                }
13725            }            
13726
13727            //fetch data
13728            $finalData = $lessonData['data'];
13729            $finalData['user_name'] = $this->Auth->user('nickname');
13730
13731            //query teacher name
13732            $teacherData = $this->Teacher->find('first', array(
13733                'fields' => 'name',
13734                'conditions' => array('Teacher.id' => $finalData['teacher_id']),
13735                'recursive' => -1
13736            ));
13737
13738            //set teacher name
13739            $finalData['teacher_name'] = isset($teacherData['Teacher']['name']) ? $teacherData['Teacher']['name'] : ''; 
13740
13741            //fetch problem data
13742            $problemData = $this->LessonOnairsLog->countProblematicLesson(array(
13743                'userId' => $userId,
13744                'teacherId' => $finalData['teacher_id'],
13745                'lessonData' => $lessonData['data']
13746            ));
13747
13748            // send to slack
13749            $slack = new mySlack();
13750            // set the channel, change to #nc-monitoring
13751            $slack->channel  = myTools::checkChannel("#nc-voice-trouble", "#nc-voice-trouble-dev");
13752            //type
13753            $slack->text = "```種別:通信トラブル(PC)\n";
13754            // set os and problem count
13755            $slack->text .= "本日:{$problemData['totalProblemCount']}件目({$problemData['userAgentStr']})\n";
13756            // set lecturer id and number of lesson
13757            $slack->text .= "講師ID:{$finalData['teacher_id']} ({$finalData['teacher_name']})(本日{$problemData['teacherCount']}回目)\n";
13758            // set member id and number of lesson
13759            $slack->text .= "会員ID:{$userId} ({$finalData['user_name']})(本日{$problemData['userCount']}回目)\n";
13760            // set contents
13761            $slack->text .= "内容:{$problem}\n";
13762            // set chat hash
13763            $slack->text .= "chathash: https://{$_SERVER['HTTP_HOST']}/admin/lesson-history?chat_hash={$chatHash}" . '```';
13764            // set slack user name
13765            $slack->username = "NativeCamp";
13766
13767            // send slack
13768            $resp = $slack->sendSlack(); //returns http code
13769            if ($resp) {
13770                return json_encode(array('success' => true));
13771            }
13772        }
13773        return json_encode(array('success' => false));
13774    }
13775
13776    /**
13777     * @api {post} /user/waiting/getApppreciationModal getApppreciationModal()
13778     * @apiName getApppreciationModal
13779     * @apiGroup Waiting
13780     * @apiDescription Retrieves the appreciation modal data for a specific lesson in Native Camp. It checks the appreciation status and returns the appreciation data.
13781     *
13782     * @apiBody {String} chat_hash The chat hash of the lesson.
13783     * @apiBody {String} member_type The type of the member (viewer or student).
13784     * 
13785     * @apiSuccess {Boolean} error Indicates whether there was an error.
13786     * @apiSuccess {String} [error_msg] The error message (if any).
13787     * @apiSuccess {String} [appreciation_data] The HTML element for the appreciation data.
13788     * @apiSuccess {Boolean} [appreciation_done] Indicates whether the appreciation is done.
13789     *
13790     * @apiSuccessExample {json} Success-Response:
13791     *     {
13792     *         "error": false,
13793     *         "appreciation_data": "<div>Appreciation Data</div>",
13794     *         "appreciation_done": true
13795     *     }
13796     *
13797     * @apiError {Boolean} error Indicates whether there was an error.
13798     * @apiError {String} error_msg The error message.
13799     *
13800     * @apiErrorExample {json} Error-Response:
13801     *     {
13802     *         "error": true,
13803     *         "error_msg": "An error occurred."
13804     *     }
13805     * 
13806     * @apiSampleRequest off
13807     */
13808    public function getApppreciationModal() {
13809        $this->autoRender = false;
13810        $this->layout = false;
13811
13812        if ($this->request->is('ajax')) {
13813            $response = array();
13814            $data = $this->request->data;
13815
13816            try  {
13817                if (!empty($data['member_type']) && $data['member_type'] !== 'viewer') {
13818                    // Check appreciation data
13819                    $appreciationElementData = $this->setUpAppreciationSelectionModalElement( array( 'chat_hash' => $data['chat_hash'] ) );
13820                    if(!empty($appreciationElementData['html_element'])){
13821                        $response['appreciation_data'] = $appreciationElementData['html_element'];
13822                    }
13823                    $elapsed5mins = false;
13824                    // 5mins elapsed only
13825                    $lessonExists = $this->LessonOnairsLog->isLessonEnded($data['chat_hash']);
13826                    if ($lessonExists) {
13827                        $this->LessonOnairsLog->openDBReplica();
13828                        $created = $this->LessonOnairsLog->find('first', [
13829                            'fields' => ['created'],
13830                            'conditions' => ['chat_hash' => $data['chat_hash']]
13831                        ]);
13832                        $this->LessonOnairsLog->closeDBReplica();
13833                        if (!empty($created)){
13834                            $created = $created['LessonOnairsLog']['created'];
13835                            $now = date('Y-m-d H:i:s');
13836                            $elapsed5mins = ( strtotime($now) - strtotime($created)) > 300;
13837                        }
13838                    }
13839                    $response['has_elapsed'] = $elapsed5mins;
13840                    $response['appreciation_done'] = $this->getAppreciationStatus($data['chat_hash']);
13841                    $response['error'] = false;
13842                }
13843                return json_encode($response);
13844                
13845            } catch (Exception $e) {
13846                $response['error'] = true;
13847                $response['error_msg'] = $e->getMessage();
13848
13849                 // - add logger
13850                 $mySlack = new mySlack();
13851                 $mySlack->channel = myTools::checkChannel("#fdci-irregular-monitoring");
13852                 $mySlack->token = "xoxb-392902820692-6499139810404-RHHGc6Z5ZB9o2KkiGhzTTtlQ";
13853                 $mySlack->username = "GetAppreciationModalFailed";
13854                 $mySlack->text = "```";
13855                 $mySlack->text .= "Message : ". $e->getMessage() ."\n";
13856                 $mySlack->text .= "Chat-hash: ". $data['chat_hash'] ."\n";
13857                 $mySlack->text .= "Student ID: ". $this->Auth->user('id') ."\n";
13858                 $mySlack->text .= "UA: ". $_SERVER['HTTP_USER_AGENT'] ."\n";
13859                 $mySlack->text .= "referrer: ". $_SERVER['HTTP_REFERER'] ."\n";
13860                 $mySlack->text .= "```";
13861                 // - send slack message
13862                 $mySlack->sendSlack();
13863                return json_encode($response);
13864            }
13865        }
13866    }
13867
13868    private function getAppreciationStatus($chatHash) {
13869        $doneAppreciation = false;
13870        $appreFields = array(
13871            'TeacherCoinBox.has_tips',
13872            'TeacherCoinBox.done_flg'
13873        );
13874        $checkCoinBoxData = $this->TeacherCoinBox->getData(array('chat_hash' => $chatHash), $appreFields);
13875        if(
13876            $checkCoinBoxData && 
13877            (isset($checkCoinBoxData['TeacherCoinBox']['has_tips']) && $checkCoinBoxData['TeacherCoinBox']['has_tips']) ||
13878            (isset($checkCoinBoxData['TeacherCoinBox']['done_flg']) && $checkCoinBoxData['TeacherCoinBox']['done_flg'])
13879        ) {
13880            $doneAppreciation = true;
13881        }
13882
13883        return $doneAppreciation;
13884    }
13885
13886    /**
13887     * @api {post} /user/waiting/getEvaluationDetail getEvaluationDetail()
13888     * @apiName getEvaluationDetail
13889     * @apiGroup Waiting
13890     * @apiDescription Retrieves the evaluation detail for a specific lesson in Native Camp. It checks if the user has already submitted an evaluation for the lesson.
13891     *
13892     * @apiBody {String} chat_hash The chat hash of the lesson.
13893     * @apiBody {String} [member_type] The type of the member (viewer or student).
13894     * 
13895     * @apiSuccess {Boolean} status Indicates whether the evaluation has been submitted.
13896     *
13897     * @apiSuccessExample {json} Success-Response:
13898     *     {
13899     *         "status": true
13900     *     }
13901     *
13902     * @apiError {String} error Message indicating the error.
13903     *
13904     * @apiErrorExample {json} Error-Response:
13905     *     {
13906     *         "error": "Invalid request."
13907     *     }
13908     * 
13909     * @apiSampleRequest off
13910     */
13911    public function getEvaluationDetail() {
13912        $this->autoRender = false;
13913        $this->layout = false;
13914        $doneReview['status'] = false;
13915        if ($this->request->is('ajax')) {
13916            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : '';
13917            //-check if viewer
13918            if (isset($this->request->data['member_type']) && $this->request->data['member_type'] == 'viewer') {
13919                $eval = $this->ViewersClassEvaluation->find('first', [
13920                    'conditions' => [
13921                        'ViewersClassEvaluation.user_id' => $this->Auth->user('id'),
13922                        'ViewersClassEvaluation.chat_hash' => $chatHash
13923                    ]
13924                ]);
13925                $doneReview['status'] = !empty($eval);        
13926            } else {
13927                if ($this->UsersClassEvaluation->findByChatHash($chatHash)) {
13928                    $doneReview['status'] = true;
13929                }
13930            }
13931        }
13932        return json_encode($doneReview);
13933    }
13934    /**
13935     * @api {post} /user/waiting/resetLessonReviewModal resetLessonReviewModal()
13936     * @apiName resetLessonReviewModal
13937     * @apiGroup Waiting
13938     * @apiDescription Resets the lesson review modal status for a specific lesson and user in Native Camp. It deletes the modal status from the cache.
13939     *
13940     * @apiBody {String} chatHash The chat hash of the lesson.
13941     * @apiBody {String} userId The ID of the user.
13942     * 
13943     * @apiSuccess {Boolean} res Indicates whether the operation was successful.
13944     *
13945     * @apiSuccessExample {json} Success-Response:
13946     *     {
13947     *         "res": true
13948     *     }
13949     *
13950     * @apiError {String} error Message indicating the error.
13951     *
13952     * @apiErrorExample {json} Error-Response:
13953     *     {
13954     *         "error": "Invalid request."
13955     *     }
13956     * 
13957     * @apiSampleRequest off
13958     */
13959    public function resetLessonReviewModal() {
13960        $this->autoRender = false;
13961        $this->layout = false;
13962        if ($this->request->is('ajax')) {
13963            $chatHash = $this->request->data('chatHash');
13964            $userId = $this->request->data('userId');
13965            $memcached = new myMemcached();
13966            $modalStatus = $memcached->get('lesson-review-modal-'. $chatHash .'-'. $userId);
13967            if ($modalStatus !== false) {
13968                $memcached->delete('lesson-review-modal-' . $chatHash .'-'. $userId);
13969            }
13970        }
13971        echo json_encode(array('res' => true));
13972    }
13973
13974    /**
13975     * @api {post} /user/waiting/finishOnlineLesson finishOnlineLesson()
13976     * @apiName finishOnlineLesson
13977     * @apiGroup Waiting
13978     * @apiDescription Finishes an online lesson for the authenticated user in Native Camp. It retrieves lesson details, updates lesson status, and returns the lesson summary.
13979     *
13980     * @apiBody {String} chatHash The chat hash of the lesson.
13981     * 
13982     * @apiSuccess {Boolean} lessonHistoryExist Indicates whether the lesson history exists.
13983     * @apiSuccess {String} ageRange The age range of the user.
13984     * @apiSuccess {Object} logDetail The lesson log details.
13985     * @apiSuccess {Object} lessonOnAirData The lesson on-air data.
13986     * @apiSuccess {Object} teacherDetailData The teacher detail data.
13987     * @apiSuccess {Object} teacherData The teacher data.
13988     * @apiSuccess {Array} avatarTeacherIdArr The array of avatar teacher IDs.
13989     * @apiSuccess {String} teacherName The name of the teacher.
13990     * @apiSuccess {String} teacherNameJA The Japanese name of the teacher.
13991     * @apiSuccess {String} teacherImage The image URL of the teacher.
13992     * @apiSuccess {String} urlLink The URL link to the teacher's detail page.
13993     * @apiSuccess {String} favTeaherId The favorite teacher ID.
13994     * @apiSuccess {String} counselorImageUrl The image URL of the counselor.
13995     * @apiSuccess {String} textbookImage The image URL of the textbook.
13996     * @apiSuccess {String} courseTitle The title of the course.
13997     * @apiSuccess {String} subCategoryLabel The label of the subcategory.
13998     * @apiSuccess {String} chapterTitle The title of the chapter.
13999     * @apiSuccess {Boolean} lessonTrouble Indicates whether there was a lesson trouble.
14000     * @apiSuccess {String} userToken The user token.
14001     * @apiSuccess {Object} finishLessonUser The user data.
14002     * @apiSuccess {String} chat_hash The chat hash of the lesson.
14003     * @apiSuccess {Boolean} lesson_review_flg Indicates whether the lesson review flag is set.
14004     * @apiSuccess {Boolean} isDefaulTextbook Indicates whether the textbook is the default textbook.
14005     * @apiSuccess {Boolean} firstSelectedDummy Indicates whether the first selected textbook is a dummy.
14006     * @apiSuccess {Boolean} allowEvaluation Indicates whether the teacher evaluation is allowed.
14007     * @apiSuccess {Object} getActiveCampaign The active campaign data.
14008     * @apiSuccess {Boolean} firstLesson Indicates whether it is the first lesson.
14009     * @apiSuccess {Boolean} hideTextbookChangeModal Indicates whether to hide the textbook change modal.
14010     * @apiSuccess {String} textbookCategoryType The type of the textbook category.
14011     * @apiSuccess {String} memberType The type of the member.
14012     * @apiSuccess {String} nickname The nickname of the user.
14013     * @apiSuccess {Number} textbookCategoryId The ID of the textbook category.
14014     * @apiSuccess {Number} isLiveFlg Indicates whether the lesson is live.
14015     * @apiSuccess {Boolean} lessonReviewModalOn Indicates whether the lesson review modal is on.
14016     * @apiSuccess {String} user_language The language of the user.
14017     *
14018     * @apiSuccessExample {json} Success-Response:
14019     *     {
14020     *         "lessonHistoryExist": true,
14021     *         "ageRange": "20-30",
14022     *         "logDetail": {...},
14023     *         "lessonOnAirData": {...},
14024     *         "teacherDetailData": {...},
14025     *         "teacherData": {...},
14026     *         "avatarTeacherIdArr": [...],
14027     *         "teacherName": "John Doe",
14028     *         "teacherNameJA": "ジョン・ドウ",
14029     *         "teacherImage": "http://example.com/image.jpg",
14030     *         "urlLink": "/waiting/detail/1",
14031     *         "favTeaherId": "1",
14032     *         "counselorImageUrl": "http://example.com/counselor.jpg",
14033     *         "textbookImage": "http://example.com/textbook.jpg",
14034     *         "courseTitle": "Course Title",
14035     *         "subCategoryLabel": "Subcategory Label",
14036     *         "chapterTitle": "Chapter Title",
14037     *         "lessonTrouble": false,
14038     *         "userToken": "example_token",
14039     *         "finishLessonUser": {...},
14040     *         "chat_hash": "example_chat_hash",
14041     *         "lesson_review_flg": 1,
14042     *         "isDefaulTextbook": false,
14043     *         "firstSelectedDummy": false,
14044     *         "allowEvaluation": 1,
14045     *         "getActiveCampaign": {...},
14046     *         "firstLesson": false,
14047     *         "hideTextbookChangeModal": "false",
14048     *         "textbookCategoryType": "Type",
14049     *         "memberType": "student",
14050     *         "nickname": "nickname",
14051     *         "textbookCategoryId": 1,
14052     *         "isLiveFlg": 0,
14053     *         "lessonReviewModalOn": false,
14054     *         "user_language": "en"
14055     *     }
14056     *
14057     * @apiError {String} error Message indicating the error.
14058     *
14059     * @apiErrorExample {json} Error-Response:
14060     *     {
14061     *         "error": "Invalid request."
14062     *     }
14063     * 
14064     * @apiSampleRequest off
14065     */
14066    public function finishOnlineLesson() {
14067        $this->autoRender = false;
14068        $this->layout = false;
14069        if ($this->request->is('ajax')) {
14070            $chatHash = $this->request->data('chatHash');
14071        
14072            // 4372 textbook name cached
14073            $memcached = new myMemcached();
14074            $textbookNamesCached = $memcached->get(Configure::read('textbook_names_cache_key'));
14075
14076            $userId = $this->Auth->user('id');
14077            $this->Session->delete('lesson.proceedFlg');
14078            //CheckHash
14079            $this->LessonOnairsLog->openDBReplica();
14080            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
14081            $lessonHistoryExist = true;
14082            $this->LessonOnairsLog->closeDBReplica();
14083            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
14084                $this->LessonOnair->openDBReplica();
14085                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
14086                $lessonHistoryExist = false;
14087                $this->LessonOnair->closeDBReplica();
14088                if(!$allData) {
14089                    die();
14090                }
14091            }
14092
14093            $response['lessonHistoryExist'] = $lessonHistoryExist;
14094            $userValidForSSBEDT = false;
14095            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
14096                $userValidForSSBEDT = true;
14097            }
14098
14099            $param = array( 
14100                "user_id" => $userId,
14101                "select_method" => "first",
14102                "env_flag" => "all",
14103                'connect_id' => $allData['Connect']['id'],
14104                "user_locale" => $this->localizeDir,
14105                "userValidForSSBEDT" => $userValidForSSBEDT
14106            );
14107            $textbookData = $this->Textbook->getTextbooks($param);
14108            
14109            $lessonUserData = (isset($allData['User'])) ? new UserTable($allData['User']) : null;
14110            
14111            $response['ageRange'] = $lessonUserData->getAgeRange();
14112            $response['logDetail'] = new LessonOnairsLogTable($allData['LessonOnairsLog']);
14113            if(isset($allData['LessonOnairsLog'])) {
14114                $response['lessonOnAirData'] = new LessonOnairsLogTable($allData['LessonOnairsLog']);
14115
14116            } else if(isset($allData['LessonOnair'])) {
14117                $response['lessonOnAirData'] = new LessonOnairTable($allData['LessonOnair']);
14118            } else {
14119                $response['lessonOnAirData'] = null;
14120            }
14121            $teacherData = new TeacherTable($allData['teacher']);
14122            $response['teacherDetailData'] = new TeacherDetailTable($allData['TeacherDetail']);
14123            
14124            $response['teacherData'] = $teacherData;
14125            $response['avatarTeacherIdArr'] = Configure::read("default_avatar_detail");
14126            $response['teacherName'] = $teacherData->name;
14127            $response['teacherNameJA'] = $teacherData->jp_name;
14128            $response['teacherImage'] = $teacherData->getImageUrl();
14129            $response['urlLink'] = "/waiting/detail/".$teacherData->getId();
14130            $response['favTeaherId'] = $teacherData->id;
14131            if ($teacherData->counseling_flg) {
14132                $counselorImageUrl = $teacherData->getProfileImage(Configure::read('default_counselor_detail'));
14133                $response['counselorImageUrl'] = $counselorImageUrl;
14134                $response['teacherName'] = "Counselor";
14135                $response['teacherNameJA'] = "カウンセラー";
14136                $response['teacherImage'] = $counselorImageUrl['image_url'];
14137                $response['urlLink'] = "/counselor_detail";
14138            }
14139            // avatar teacher
14140            if ($teacherData->avatar_id && $teacherData->avatar_flg) {
14141                if ($teacherData->avatar_id) {
14142                    $response['teacherName'] = $teacherData->getAvatarParentNameEn();
14143                    $response['teacherNameJA'] =  $teacherData->getAvatarParentName();
14144                    $response['teacherImage'] = $teacherData->getAvatarParentImageUrl();
14145                    $response['favTeaherId'] = $teacherData->avatar_id;
14146                    $response['urlLink'] = "/avatar_detail/".$teacherData->avatar_id;
14147                }
14148            }
14149
14150            $data = $textbookData['res_data'];
14151            $order = (isset($textbookNamesCached[$data['TextbookConnect']['id']]['order']) && $textbookNamesCached[$data['TextbookConnect']['id']]['order']) ? $textbookNamesCached[$data['TextbookConnect']['id']]['order'] : '';
14152
14153            //- check if for live viewing
14154            $onairData = isset($allData['LessonOnairsLog']) ? $allData['LessonOnairsLog'] : $allData['LessonOnair'];
14155            $onAirUserId = $onairData['user_id'];
14156            $isLive = $onairData['live_lesson_flg'];
14157
14158            //- check member type
14159            $memberType = 'student';
14160            $liveSystemTrouble = 0;
14161
14162            if ($isLive && $onAirUserId != $userId) {
14163                $memberType = 'viewer';
14164                //- update end time
14165                $this->LessonOnairsViewersLog->endTime([
14166                    'chat_hash'     => $chatHash,
14167                    'user_id'         => $userId,
14168                    'guest_viewer'     => empty($userId) ? 1 : 0,
14169                    'viewer_ip'         => myTools::getClientIP()
14170                ]);
14171
14172                $liveLog = $this->LessonOnairsViewer->find('first', [
14173                    'fields' => [
14174                        'LessonOnairsViewer.live_system_trouble'
14175                    ],
14176                    'conditions' => [
14177                        'LessonOnairsViewer.user_id' => $userId,
14178                        'LessonOnairsViewer.chat_hash' => $chatHash
14179                    ]
14180                ]);
14181                $liveSystemTrouble = (!empty($liveLog['LessonOnairsViewer']['live_system_trouble'])) ? 1 : 0;
14182
14183                if ($liveLog) {
14184                    // process live lesson coupon grant
14185                    $this->LessonOnairsViewer->processLiveLessonCouponGrant($this->sharedUserData['User'], $chatHash);
14186                }
14187            }
14188
14189            $userValidForSSBEDT = false;
14190            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
14191                $userValidForSSBEDT = true;
14192            }
14193            $param = array(
14194                "user_id" => $userId,
14195                "select_method" => "first",
14196                "env_flag" => "all",
14197                'connect_id' => $allData['Connect']['id'],
14198                "user_locale" => $this->localizeDir,
14199                "userValidForSSBEDT" => $userValidForSSBEDT
14200            );
14201            //NJ-12326
14202            if ($userId && isset($allData['Connect']['category_id']) && $allData['Connect']['category_id']) {
14203                $corporateParams = array('user_id' => $userId);
14204                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
14205
14206                if ($corporateTextbookControlFlg == 1) {
14207                    $categoryData = $this->TextbookCategory->getKidsCategoryTypesById($allData['Connect']['category_id']);
14208                    if (!empty($categoryData)) {
14209                        $param['include_kids_category'] = $allData['Connect']['category_id'];
14210                    }
14211                }
14212            }
14213            $textbookData = $this->Textbook->getTextbooks($param);
14214
14215            $data = $textbookData['res_data'];
14216
14217            // textbook image
14218            $response['textbookImage'] = $data['TextbookCategory']['image_small_url'];
14219
14220            $order = (isset($textbookNamesCached[$data['TextbookConnect']['id']]['order']) && $textbookNamesCached[$data['TextbookConnect']['id']]['order']) ? $textbookNamesCached[$data['TextbookConnect']['id']]['order'] : '';
14221            
14222            $courseTitle = (isset($data['TextbookCategory']['name'])) ? $data['TextbookCategory']['name'] : '';
14223            $subCategoryNameLabel = (isset($data['TextbookSubcategory']['name'])) ? $data['TextbookSubcategory']['name'] : '';
14224            $chapterTitle = isset($textbookNamesCached[$data['TextbookConnect']['id']]['jpn'] ) ?  $textbookNamesCached[$data['TextbookConnect']['id']]['jpn'] : ((isset($data['Textbook']['name'])) ? $order.$data['Textbook']['name'] : '');
14225
14226            #global textbook information
14227            $globalCourseTitle = isset($data['GlobalTextbookCategory']['gl_name']) ? $data['GlobalTextbookCategory']['gl_name'] : $courseTitle;
14228            $subCategoryNameLabel = isset($data['GlobalTextbookSubcategory']['gl_name']) ? $data['GlobalTextbookSubcategory']['gl_name'] : $subCategoryNameLabel;
14229            $globalChapterTitle = isset($data['GlobalTextbook']['gl_name']) ? $order.$data['GlobalTextbook']['gl_name'] : $chapterTitle;
14230
14231            // check for main topic
14232            if ( isset($data['Textbook']['main_topic_id']) && $data['Textbook']['main_topic_id'] ) {
14233                $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
14234                $textbookMainTopicName = ClassRegistry::init('Textbook')->getTextbookMainTopicName($data['Textbook']['id'],$langId);
14235                if ($textbookMainTopicName) {
14236                    $subCategoryNameLabel = $textbookMainTopicName;
14237                }
14238            }
14239
14240            //get teacher id from logs
14241            $teacherId = isset($allData['LessonOnairsLog']['teacher_id']) ? $allData['LessonOnairsLog']['teacher_id'] : $allData['LessonOnair']['teacher_id']; 
14242
14243            // - check if the queried data has teacher rank coin id
14244            if(isset($allData['teacher']['rank_coin_id'])) {
14245                $teacher_rank_coin_id = $allData['teacher']['rank_coin_id'];
14246
14247            } else {
14248                // - get teacher rank coin id
14249                $this->Teacher->openDBReplica();
14250                $coinId = $this->Teacher->find('first',array(
14251                    'fields' => array('Teacher.rank_coin_id'),
14252                    'conditions' => array('Teacher.id' => $teacherId),
14253                    'recursive' => -1
14254                ));
14255                $this->Teacher->closeDBReplica();
14256                $teacher_rank_coin_id = isset($coinId['Teacher']['rank_coin_id']) ? $coinId['Teacher']['rank_coin_id'] :  null;
14257
14258            }
14259
14260            $showRatingFlg = $this->TeacherRankCoin->find('first',array(
14261                    'fields' => array('TeacherRankCoin.strength_weakness_flag', 'TeacherRankCoin.id'),
14262                    'conditions' => array('TeacherRankCoin.id' => $teacher_rank_coin_id)
14263                ));
14264            $response['showRatingFlg'] = $showRatingFlg['TeacherRankCoin']['strength_weakness_flag'];
14265
14266            $user = (isset($this->sharedUserData['User'])) ? new UserTable($this->sharedUserData['User']) : null;
14267            $response['userMembershipIndex'] = null;
14268            if (!empty($user)) {
14269                $userMembershipIndex = $user->getMembershipTypeIndex();
14270                $response['userMembershipIndex'] = $userMembershipIndex;
14271            }            
14272
14273            $noNextTextbookModal = array(
14274                11, //'Corporate Limited Plan(Company payment-Bank transfer)'
14275                35, //'Study Sapuri ENGLISH School Plan (Paid)',
14276                16, //'Corporate Light Plan(Company payment-Bank transfer)',
14277                25, //'Corporate Light Plan (Company payment-Card)',
14278                17, //'Corporate Light Plan (Individual payment)',
14279            );
14280
14281            $response['noNextTextbookModal'] = $noNextTextbookModal;
14282
14283            $counselorDetail = $this->Teacher->getDefaultCounselorDetail();
14284            $this->set('counselorDetail', $counselorDetail);
14285
14286            if (is_null($allData['teacher']['first_lesson_date'])) {
14287                if (isset($allData['LessonOnair'])) {
14288                    $allData['teacher']['first_lesson_date'] = $allData['LessonOnair']['end_time'];
14289                } elseif (isset($allData['LessonOnairsLog'])) {
14290                    $allData['teacher']['first_lesson_date'] = $allData['LessonOnairsLog']['end_time'];
14291                }
14292            }
14293
14294            //NC-4572
14295            $userID = $this->Auth->user('id');
14296
14297            $lessonTrouble = isset($allData['LessonOnairsLog']['lesson_system_trouble']) ? intval($allData['LessonOnairsLog']['lesson_system_trouble']) : intval($allData['LessonOnair']['lesson_system_trouble']); 
14298
14299            $response['lessonTrouble'] =  ($lessonTrouble || $liveSystemTrouble);
14300            $response['userToken'] = $this->Auth->user('api_token');
14301            $response['courseTitle'] = $globalCourseTitle;
14302            $response['subCategoryLabel'] = $subCategoryNameLabel;
14303            $response['chapterTitle'] = $globalChapterTitle;
14304            $response['finishLessonUser'] = $user;
14305            $response['chat_hash'] = $chatHash;
14306            $response['lesson_review_flg'] = isset($user->lesson_review_flg) ? $user->lesson_review_flg : 0;
14307
14308            // NJ-8416
14309            $env = Configure::read('ENVIRONMENT');
14310            $defaultTextbookId = Configure::read("default_dummy_textbook.{$env}");
14311            $dummyConnectId = Configure::read("dummy_textbook_connect_id.{$env}");
14312
14313            // - check end lesson textbook is dummy
14314            $isDefaulTextbook = ($defaultTextbookId == $allData['Connect']['category_id']) ? true : false;
14315
14316            $response['isDefaulTextbook'] = $isDefaulTextbook;
14317
14318            // - get first selected textbook connect_id
14319            $userFirstSelectedTextbook = $this->User->getUserData(
14320                array(
14321                    'id' => $userId
14322                ),
14323                array(
14324                    'first_selected_textbook'
14325                ),
14326                'first'
14327            );
14328
14329            // - check first selected textbook connect_id is dummy
14330            $firstSelectedDummy = ($userFirstSelectedTextbook['User']['first_selected_textbook'] == $dummyConnectId) ? true : false;
14331            $response['firstSelectedDummy'] = $firstSelectedDummy;
14332
14333
14334            // NJ-33170
14335            $lessonConnectId = isset($allData['LessonOnairsLog']['connect_id']) && $allData['LessonOnairsLog']['connect_id'] ? $allData['LessonOnairsLog']['connect_id'] : $allData['LessonOnair']['connect_id'];
14336            // get lesson textbook category id
14337            $this->TextbookConnect->openDbReplica();
14338            $textbookConnect = $this->TextbookConnect->find('first', array(
14339                'fields' => array('TextbookConnect.category_id'),
14340                'conditions' => array('TextbookConnect.id' => $lessonConnectId)
14341            ));
14342            $this->TextbookConnect->closeDbReplica();
14343            $lessonTextbookCategoryId = isset($textbookConnect['TextbookConnect']['category_id']) ? $textbookConnect['TextbookConnect']['category_id'] : null;
14344            
14345            $teacherEvalRestrictedTextbook = Configure::read("teacher_evaluation_restricted_textbook.{$env}");
14346            // disable teacher textbook evaluation if textbook is: (Textbook selection after entering the lesson)
14347            $allowEvaluation = $lessonTextbookCategoryId == $teacherEvalRestrictedTextbook ? 0 : 1;
14348
14349            $response['allowEvaluation'] = $allowEvaluation;
14350
14351            // [START]--- Campaign modal
14352            $getActiveCampaignParams = array(
14353                'counseling_flg' => isset($allData['teacher']['counseling_flg']) ? $allData['teacher']['counseling_flg'] : 0,
14354                'avatar_flg' => isset($allData['teacher']['avatar_flg']) ? $allData['teacher']['avatar_flg'] : 0,
14355                'chat_hash' => $chatHash,
14356                'memberType' => $memberType
14357            );
14358            $response['getActiveCampaign'] = $this->getActiveCampaign($getActiveCampaignParams);
14359            // [ END ]--- Campaign modal
14360
14361            // NC-7922 sapuri first lesson
14362            if ($this->studySapuriId) {
14363                $firstLesson = $this->UserFirstLesson->checkFirstLesson(array('user_id' => $userID));
14364                if ($firstLesson && $firstLesson['UserFirstLesson']['chat_hash'] == $chatHash) {
14365                    $oUserData = new UserTable($this->sharedUserData['User']);
14366                    $sapuriPlan = $oUserData->isStudySapuri();
14367                    $stusapTextType = Configure::read('studysapuri_textbook_category_types');
14368                    $topList = $this->CommonTeacherStatus->getSapuriRecommendTeacher($stusapTextType[$sapuriPlan]);
14369                    $firstLesson = true;
14370
14371                    $response['reserveRecommend'] = $topList;
14372                } else {
14373                    $firstLesson = false;
14374                }
14375            } else {
14376                $firstLesson = false;
14377            }
14378
14379            $response['firstLesson'] = $firstLesson;
14380
14381            // NC-7592 - Hide textbookChange modal after lesson if reserved lesson & disable button if no next textbook chapter
14382            $isReservedLesson = 2;
14383            $hideTextbookChangeModal = $enableNextTextbookChapterButton = 'false';
14384            $latestPresetTextbookConnect_id = (int)$data['TextbookConnect']['id'];
14385
14386            //NJ-3626 Optimize PC /lesson-finish page
14387            $lessonOnairLatestData = $this->LessonOnair->getLatestLessonOnairDetailsOfUserAndTeacher($userId, $teacherId);
14388            $lessonOnairLatestDataFlg = false;
14389            if(isset($lessonOnairLatestData) && $lessonOnairLatestData) {
14390                $lessonOnairLatestDataFlg = true;
14391                $lessonOnairLatest_connectId = (int)$lessonOnairLatestData['LessonOnair']['connect_id'];
14392                $lessonOnairLatest_lessonType = (int)$lessonOnairLatestData['LessonOnair']['lesson_type'];
14393            } else {
14394                $lessonOnairLogsLatestData = $this->LessonOnairsLog->getLatestLessonLogsDetailsOfUserAndTeacher($userID, $teacherId);
14395                if(isset($lessonOnairLogsLatestData) && $lessonOnairLogsLatestData) {
14396                    $lessonOnairLogsLatest_connectId = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['connect_id'];
14397                    $lessonOnairLogsLatest_lessonType = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['lesson_type'];
14398                }
14399            }
14400
14401            // - initialize empty variable
14402            $isLatestPresetTextbookMadeDuringLastLesson = [];
14403            $latestPresetTextbookParams = [];
14404
14405            // For hiding of textbookchange modal (if reserved lesson & not studySapuri)
14406            if ($lessonOnairLatestDataFlg) {
14407                $latestPresetTextbookParams = array (
14408                    'userId' => $userID,
14409                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
14410                    'lessonOnairLatest_startTime' => $lessonOnairLatestData['LessonOnair']['start_time'],
14411                    'lessonOnairLatest_endTime' => $lessonOnairLatestData['LessonOnair']['end_time']
14412                );
14413
14414            // - if has lesson onairs log
14415            } else if ($lessonOnairLogsLatestData) {
14416                $latestPresetTextbookParams = array (
14417                    'userId' => $userID,
14418                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
14419                    'lessonOnairLogsLatest_startTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['start_time'],
14420                    'lessonOnairLogsLatest_endTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['end_time']
14421                );
14422
14423            }
14424
14425            $response['isStudySapuriTosUser'] = $this->isStudySapuriTosUser;
14426            // - if has parameters for fetching latest textbook parameters
14427            if ($latestPresetTextbookParams) {
14428                $isLatestPresetTextbookMadeDuringLastLesson = $this->UsersTextbookInfo->checkLatestUserTextbookInfoChangedDuringLesson($latestPresetTextbookParams);
14429            }
14430
14431            // -  check sapuri ID
14432            if(!isset($this->studySapuriId) || !$this->studySapuriId) {
14433                if (isset($lessonOnairLatestDataFlg)) {
14434                    if (is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
14435                        && $latestPresetTextbookConnect_id == $lessonOnairLatest_connectId && $lessonOnairLatest_lessonType == $isReservedLesson
14436                    ) {
14437                        $hideTextbookChangeModal = 'true';
14438                    }
14439                } else {
14440                    if (
14441                        is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
14442                        && $latestPresetTextbookConnect_id == $lessonOnairLogsLatest_connectId &&  $lessonOnairLogsLatest_lessonType == $isReservedLesson
14443                    ) {
14444                        $hideTextbookChangeModal = 'true';
14445                    }
14446                }
14447            }
14448            
14449            // NJ-3696
14450            if($lessonHistoryExist) {
14451                $response['textbookCategoryType'] = $this->TextbookCategory->getTextbookCategoryType($allData['LessonOnairsLog']['textbook_category_id']);
14452            } else {
14453                $response['textbookCategoryType'] = $this->TextbookCategory->getTextbookCategoryType($allData['LessonOnair']['textbook_category_id']);
14454            }
14455
14456            //TODO: NJ-59368 - send is callan textbook category
14457            $response['isCallanTextbook'] = in_array($response['textbookCategoryType'], Configure::read('callan_textbook_type'));
14458
14459            $response['hideTextbookChangeModal'] = $hideTextbookChangeModal;
14460
14461            $response['memberType'] = $memberType;
14462            $response['nickname'] = isset($this->sharedUserData['User']['nickname']) ? $this->sharedUserData['User']['nickname'] : $this->Auth->user('nickname');
14463            $response['textbookCategoryId'] = (int)$allData['Connect']['category_id'];
14464            $response['isLiveFlg'] = (int)$isLive;
14465            $response['lessonReviewModalOn'] = false;
14466            $response['network_review_flg'] = $this->sharedUserData['User']['network_review_flg']; // include the user's setting 'network_review_flg' in the response
14467            if ($this->Auth->User('id')) {
14468                $reviewLessonCache = $memcached->get('lesson-review-modal-'. $chatHash .'-'. $this->Auth->User('id'));
14469                if ($reviewLessonCache !== false && $reviewLessonCache == 1) {
14470                    $response['lessonReviewModalOn'] = true;
14471                }
14472            }
14473            $response['user_language'] = $this->localizeDir;
14474            return json_encode($response);
14475        }
14476        
14477    }
14478
14479    /**
14480     * @api {post} /user/waiting/getCounselorLessonHistory getCounselorLessonHistory()
14481     * @apiName getCounselorLessonHistory
14482     * @apiGroup Waiting
14483     * @apiDescription Retrieves the lesson history for a specific counselor in Native Camp. It returns the lesson history details including textbook information, lesson time, and URLs for chat logs and message logs.
14484     *
14485     * @apiBody {String} teacherId The ID of the teacher.
14486     * 
14487     * @apiSuccess {Boolean} res Indicates whether the request was successful.
14488     * @apiSuccess {Array} lessonHistory The lesson history details.
14489     * @apiSuccess {String} lessonHistory.lesson_number The lesson number.
14490     * @apiSuccess {String} lessonHistory.chatStartJPDate The start date of the chat in Japanese format.
14491     * @apiSuccess {String} lessonHistory.chatStartTime The start time of the chat.
14492     * @apiSuccess {String} lessonHistory.lessonHistoryTime The duration of the lesson in minutes.
14493     * @apiSuccess {String} lessonHistory.textbook_url The URL for the textbook details.
14494     * @apiSuccess {String} lessonHistory.categoryNameLabel The label for the category name.
14495     * @apiSuccess {String} lessonHistory.subCategoryNameLabel The label for the subcategory name.
14496     * @apiSuccess {String} lessonHistory.textbookNameLabel The label for the textbook name.
14497     * @apiSuccess {Number} lessonHistory.rate The rating for the lesson.
14498     * @apiSuccess {String} lessonHistory.chat_logs_url The URL for the chat logs.
14499     * @apiSuccess {Boolean} lessonHistory.has_message_logs Indicates whether the lesson has message logs.
14500     * @apiSuccess {String} lessonHistory.message_logs_url The URL for the message logs.
14501     * @apiSuccess {Number} lessonHistory.audio_count_log The audio count log.
14502     * @apiSuccess {String} lessonHistory.textbook_image The URL for the textbook image.
14503     *
14504     * @apiSuccessExample {json} Success-Response:
14505     *     {
14506     *         "res": true,
14507     *         "lessonHistory": [
14508     *             {
14509     *                 "lesson_number": "1",
14510     *                 "chatStartJPDate": "2023-01-01",
14511     *                 "chatStartTime": "10:00",
14512     *                 "lessonHistoryTime": "30分",
14513     *                 "textbook_url": "/textbook/page-detail/1/1",
14514     *                 "categoryNameLabel": "Category Name",
14515     *                 "subCategoryNameLabel": "Subcategory Name",
14516     *                 "textbookNameLabel": "Textbook Name",
14517     *                 "rate": 5,
14518     *                 "chat_logs_url": "/chat-history/1/1",
14519     *                 "has_message_logs": true,
14520     *                 "message_logs_url": "/lesson-message/detail/1",
14521     *                 "audio_count_log": 1,
14522     *                 "textbook_image": "http://example.com/image.jpg"
14523     *             },
14524     *             ...
14525     *         ]
14526     *     }
14527     *
14528     * @apiError {Boolean} res Indicates whether the request was successful.
14529     *
14530     * @apiErrorExample {json} Error-Response:
14531     *     {
14532     *         "res": false
14533     *     }
14534     * 
14535     * @apiSampleRequest off
14536     */
14537    public function getCounselorLessonHistory() {
14538        $this->autoRender = false;
14539        $this->layout = false;
14540        $response = json_encode(array('res' => false)); // default
14541        
14542        if($this->request->is('post')) {
14543            $post = $this->request->data;
14544            if (!isset($post['teacherId']) && $post['teacherId']) {
14545                return json_encode($response);
14546            }
14547            $teacherId = $post['teacherId'] ?? null;
14548
14549            //NC-7984 start
14550            $lesson_history_data = $this->LessonSchedule->latestCounselorLessonHistory($this->Auth->user('id'), 10);
14551            if(!empty($lesson_history_data) && $lesson_history_data) {
14552                $textbookNamesCachedArr = $lesson_history_data['textbookNamesCachedArr'];
14553
14554                foreach ($lesson_history_data['lessonHistory'] as $key => $value) {
14555                    $dteStart = new DateTime($value['LessonOnairsLog']['start_time']);
14556                    $dteEnd   = new DateTime($value['LessonOnairsLog']['end_time']);
14557
14558                    $logDetail = new LessonOnairsLogTable($value['LessonOnairsLog']);
14559
14560                    $lessonTime = $dteStart->diff($dteEnd);
14561                    $lessonHistoryTime = $lessonTime->format("%I");
14562
14563                    $textbookOrder = isset($textbookNamesCachedArr[$value['TextbookConnect']['id']]['order']) ? $textbookNamesCachedArr[$value['TextbookConnect']['id']]['order'] : '';
14564
14565                    $categoryName = $value['TextbookCategory']['name'];
14566                    $subcategoryName = $value['TextbookSubategory']['name'];
14567                    $textbookName = $value['Textbook']['name'];
14568                    $textbookMainTopicName = isset($value['Textbook']['main_topic_name']) ? $value['Textbook']['main_topic_name'] : '';
14569
14570                    // - if has translated Category name
14571                    if (isset($value['GlobalTextbookCategory']['gl_name']) && $value['GlobalTextbookCategory']['gl_name']) {
14572                        $categoryName = $value['GlobalTextbookCategory']['gl_name'];
14573                    }
14574
14575                    // - if has translated subcategory name
14576                    if (isset($value['GlobalTextbookSubcategory']['gl_name']) && $value['GlobalTextbookSubcategory']['gl_name']) {
14577                        $subcategoryName = $value['GlobalTextbookSubcategory']['gl_name'];
14578                    }
14579
14580                    // - if has translated textbook name
14581                    if (isset($value['GlobalTextbook']['gl_name']) && $value['GlobalTextbook']['gl_name']) {
14582                        $textbookName = $value['GlobalTextbook']['gl_name'];
14583                    }
14584
14585                    // - set textbook name
14586                    $categoryNameLabel = $categoryName;
14587                    $subCategoryNameLabel = $subcategoryName;
14588                    $subCategoryNameLabel = $textbookMainTopicName ? $textbookMainTopicName : $subcategoryName;
14589                    $textbookNameLabel = $textbookOrder . $textbookName;
14590                    $textbook_url = "/textbook/page-detail/{$value['TextbookCategory']['type_id']}/{$value['LessonOnairsLog']['connect_id']}";
14591
14592                    $has_message_logs = !empty($value['LessonOnairsLog']['lesson_memo']) && $value['LessonOnairsLog']['lesson_memo_disp_flg'] == 1 && $value['LessonOnairsLog']['display_message'] == 1;
14593                    $message_logs_url = "/lesson-message/detail/{$value['LessonOnairsLog']['id']}";
14594                    $teacher_id = $value['LessonOnairsLog']['teacher_id'];
14595                    $chat_logs_url = "/chat-history/{$teacher_id}/{$value['LessonOnairsLog']['chat_hash']}";
14596
14597                    $lesson_history_data['lessonHistory'][$key]['lesson_number'] = $value['LessonTrackLogs']['lesson_number'];
14598                    $lesson_history_data['lessonHistory'][$key]['chatStartJPDate'] = $logDetail->chatStartJPDate($this->timeDiffSecond);
14599                    $lesson_history_data['lessonHistory'][$key]['chatStartTime'] = $logDetail->chatStartTime($this->timeDiffSecond);
14600                    $lesson_history_data['lessonHistory'][$key]['lessonHistoryTime'] = $lessonHistoryTime. __('分');
14601                    $lesson_history_data['lessonHistory'][$key]['textbook_url'] = $textbook_url;
14602                    $lesson_history_data['lessonHistory'][$key]['categoryNameLabel'] = $categoryNameLabel;
14603                    $lesson_history_data['lessonHistory'][$key]['subCategoryNameLabel'] = $subCategoryNameLabel;
14604                    $lesson_history_data['lessonHistory'][$key]['textbookNameLabel'] = $textbookNameLabel;
14605                    $lesson_history_data['lessonHistory'][$key]['rate'] = $value['usersClassEvaluations']['rate'];
14606                    $lesson_history_data['lessonHistory'][$key]['chat_logs_url'] = $chat_logs_url;
14607                    $lesson_history_data['lessonHistory'][$key]['has_message_logs'] = $has_message_logs;
14608                    $lesson_history_data['lessonHistory'][$key]['message_logs_url'] = $message_logs_url;
14609                    $lesson_history_data['lessonHistory'][$key]['audio_count_log'] = $value['LessonOnairsLog']['temp_flg1'];
14610                    $lesson_history_data['lessonHistory'][$key]['textbook_image'] = $value['TextbookCategory']['image_big_url'];
14611                }
14612                
14613                $response = json_encode(array(
14614                    'res' => true, 
14615                    'lessonHistory' => $lesson_history_data['lessonHistory']
14616                ));
14617            }
14618        }
14619        return $response;
14620    }
14621
14622    /**
14623     * @api {get} /user/waiting/speakingTestAttendance speakingTestAttendance()
14624     * @apiName speakingTestAttendance
14625     * @apiGroup Waiting
14626     * @apiDescription Retrieves the attendance status for the speaking test and counseling sessions for the authenticated user in Native Camp. It returns the URLs, CSS classes, and text for the speaking test and counseling status.
14627     * 
14628     * @apiSuccess {String} speakingTestDailyFlgUrl The URL for the daily speaking test.
14629     * @apiSuccess {String} speakingTestBusinessFlgUrl The URL for the business speaking test.
14630     * @apiSuccess {String} speakingTestDailyFlgClass The CSS class for the daily speaking test status.
14631     * @apiSuccess {String} speakingTestBusinessFlgClass The CSS class for the business speaking test status.
14632     * @apiSuccess {String} counselingFlgClass The CSS class for the counseling status.
14633     * @apiSuccess {String} speakingTestDailyFlgTxt The text for the daily speaking test status.
14634     * @apiSuccess {String} speakingTestBusinessFlgTxt The text for the business speaking test status.
14635     * @apiSuccess {String} counselingFlgTxt The text for the counseling status.
14636     *
14637     * @apiSuccessExample {json} Success-Response:
14638     *     {
14639     *         "speakingTestDailyFlgUrl": "http://example.com/en/speaking_test/daily_start",
14640     *         "speakingTestBusinessFlgUrl": "http://example.com/en/speaking_test/business_start",
14641     *         "speakingTestDailyFlgClass": "",
14642     *         "speakingTestBusinessFlgClass": "",
14643     *         "counselingFlgClass": "",
14644     *         "speakingTestDailyFlgTxt": "未受験",
14645     *         "speakingTestBusinessFlgTxt": "未受験",
14646     *         "counselingFlgTxt": "未受講"
14647     *     }
14648     *
14649     * @apiError {String} error Message indicating the error.
14650     *
14651     * @apiErrorExample {json} Error-Response:
14652     *     {
14653     *         "error": "Invalid request."
14654     *     }
14655     * 
14656     * @apiSampleRequest off
14657     */
14658    public function speakingTestAttendance(){
14659        $this->autoRender = false;
14660        $this->layout = false;
14661
14662        $speakingTestDailyFlgUrl         = myTools::getUrl() .'/'.$this->localizeDir. "/speaking_test/daily_start";
14663        $speakingTestBusinessFlgUrl     = myTools::getUrl() .'/'.$this->localizeDir. "/speaking_test/business_start";
14664        $speakingTestDailyFlgClass         = '';
14665        $speakingTestBusinessFlgClass     = '';
14666        $counselingFlgClass             = '';
14667        $speakingTestDailyFlgTxt         = __d('waiting', '未受験');
14668        $speakingTestBusinessFlgTxt     = __d('waiting', '未受験');
14669        $counselingFlgTxt                 = __d('waiting', '未受講');
14670
14671        $monthlySpeakingTestStatus = array();
14672        if ( $this->request->is('ajax') && !empty($this->sharedUserData['User']['id']) ) {
14673            $monthlySpeakingTestStatus = UserTable::monthlySpeakingTrainingStatus(array(
14674                'user_id' => $this->sharedUserData['User']['id'],
14675                'time_diff' => $this->timeDiffSecond
14676            ));
14677            //-- Speaking training daily
14678            if (!empty($monthlySpeakingTestStatus['speaking_test_daily_english_flg'])) {
14679                $speakingTestDailyFlgClass         = 'done';
14680                $speakingTestDailyFlgUrl         = myTools::getUrl().'/'.$this->localizeDir. "/speaking_test/daily_start?result=true";
14681                $speakingTestDailyFlgTxt = __d('waiting', '受験済み');
14682            }
14683            //-- Speaking training business
14684            if (!empty($monthlySpeakingTestStatus['speaking_test_business_english_flg'])) {
14685                $speakingTestBusinessFlgClass     = 'done';
14686                $speakingTestBusinessFlgUrl     = myTools::getUrl() .'/'.$this->localizeDir."/speaking_test/business_start?result=true";
14687                $speakingTestBusinessFlgTxt = __d('waiting', '受験済み');
14688            }
14689            //-- Counseling
14690            if (!empty($monthlySpeakingTestStatus['counseling_lesson_flg'])) {
14691                $counselingFlgClass = 'done';
14692                $counselingFlgTxt = __d('waiting', '受講済み');
14693            }
14694
14695            $monthlySpeakingTestStatus = array(
14696                'speakingTestDailyFlgUrl'         => $speakingTestDailyFlgUrl,
14697                'speakingTestBusinessFlgUrl'     => $speakingTestBusinessFlgUrl,
14698                'speakingTestDailyFlgClass'     => $speakingTestDailyFlgClass,
14699                'speakingTestBusinessFlgClass'     => $speakingTestBusinessFlgClass,
14700                'counselingFlgClass'             => $counselingFlgClass,
14701                'speakingTestDailyFlgTxt'         => $speakingTestDailyFlgTxt,
14702                'speakingTestBusinessFlgTxt'     => $speakingTestBusinessFlgTxt,
14703                'counselingFlgTxt'                 => $counselingFlgTxt
14704            );
14705        }
14706        return json_encode($monthlySpeakingTestStatus);
14707    }
14708
14709    /**
14710     * @api {get} /user/waiting/getRegion getRegion()
14711     * @apiName getRegion
14712     * @apiGroup Waiting
14713     * @apiDescription Retrieves the list of countries and their regions based on the user's language in Native Camp. It returns the country and region details.
14714     *
14715     * @apiSuccess {Boolean} success Indicates whether the request was successful.
14716     * @apiSuccess {Array} regionDetails The list of countries and their regions.
14717     * @apiSuccess {Object} regionDetails.country The details of a country.
14718     * @apiSuccess {String} regionDetails.country.country_name The name of the country.
14719     * @apiSuccess {Array} regionDetails.country.regions The list of regions in the country.
14720     * @apiSuccess {Object} regionDetails.country.regions.region The details of a region.
14721     * @apiSuccess {String} regionDetails.country.regions.region.id The ID of the region.
14722     * @apiSuccess {String} regionDetails.country.regions.region.region_name The name of the region.
14723     *
14724     * @apiSuccessExample {json} Success-Response:
14725     *     {
14726     *         "success": true,
14727     *         "regionDetails": [
14728     *             {
14729     *                 "country_name": "Japan",
14730     *                 "regions": [
14731     *                     {
14732     *                         "id": "1",
14733     *                         "region_name": "Kanto"
14734     *                     },
14735     *                     ...
14736     *                 ]
14737     *             },
14738     *             ...
14739     *         ]
14740     *     }
14741     *
14742     * @apiError {Boolean} success Indicates whether the request was successful.
14743     * @apiError {String} message The error message.
14744     *
14745     * @apiErrorExample {json} Error-Response:
14746     *     {
14747     *         "success": false,
14748     *         "message": "Failed to retrieve region details."
14749     *     }
14750     * 
14751     * @apiSampleRequest off
14752     */
14753    public function getRegion() {
14754        $this->autoRender = false;
14755
14756        $userLang = $this->localizeDir ? $this->localizeDir : Configure::read('original_language_default');
14757        $languageId = Configure::read('english_language_id'); // set default
14758        $languageIds = $this->CountryCode->getLanguageList(['field'=>'iso_639_1']);
14759
14760        foreach($languageIds as $key => $language) {
14761            if (strtolower($language) == strtolower($userLang)) {
14762                $languageId = $key;
14763                break;
14764            }
14765        }
14766    
14767        $countryRegions = $this->CountryRegion->getCountryResidence([], $languageId, true);
14768        $countryRegionData = array();
14769        
14770        foreach ($countryRegions as $key => $countryRegion) {
14771            $countryRegionData[$countryRegion['CountryCode']['id']]['country_name'] = !empty($countryRegion['GlobalCountryCode']['gl_name']) ? $countryRegion['GlobalCountryCode']['gl_name'] : $countryRegion['CountryCode']['country_name'];
14772            $countryRegionData[$countryRegion['CountryCode']['id']]['regions'][] = [
14773                'id' => $countryRegion['CountryRegion']['id'],
14774                'region_name' => !empty($countryRegion['GlobalCountryRegion']['gl_name']) ? $countryRegion['GlobalCountryRegion']['gl_name'] : $countryRegion['CountryRegion']['region_name']
14775            ];
14776        }
14777
14778        $response = [
14779            'success' => true,
14780            'regionDetails' => array_values($countryRegionData)
14781        ];
14782
14783        return json_encode($response);
14784    }
14785
14786
14787    //get the country and region/city if display flag is on and delete flag is 0 ; 0 = not deleted
14788    function getResidenceData($getCRData) {
14789        $residenceData = [
14790            'countryName' => '',
14791            'countryFlag' => 'other',
14792            'regionName' => ''
14793        ];
14794        if ((empty($getCRData['CountryCode']['country_name']) && empty($getCRData['CountryRegion']['region_name']))) {
14795            return $residenceData;
14796        }
14797        if ($getCRData['CountryCode']['display_flag'] != 1) {
14798            return $residenceData;
14799        }
14800        if (empty($getCRData['TeacherDetail']['country_id'])) {
14801            return $residenceData;
14802        }
14803        if ($getCRData['CountryRegion']['delete_flag'] == 1) {
14804            return $residenceData;
14805        }
14806    
14807        $residenceData['countryName'] = isset($getCRData['GlobalCountryCode']['gl_name']) ? $getCRData['GlobalCountryCode']['gl_name'] : $getCRData['CountryCode']['country_name'];
14808        $getCountryCode = $this->CountryCode->getCountryFromId($getCRData['TeacherDetail']['country_id']);
14809        if ($getCountryCode) {
14810            $countryCodeLower = strtolower($getCountryCode);
14811            $explodeCountryCode = explode(' ', $countryCodeLower);
14812            $residenceData['countryFlag'] = implode('_', $explodeCountryCode);
14813        }
14814    
14815        if (isset($getCRData['GlobalCountryRegion']['gl_name'])) {
14816            $residenceData['regionName'] = $getCRData['GlobalCountryRegion']['gl_name'];
14817        } elseif (isset($getCRData['CountryRegion']['region_name'])) {
14818            $residenceData['regionName'] = $getCRData['CountryRegion']['region_name'];
14819        }
14820
14821        return $residenceData;
14822    }
14823
14824
14825    /**
14826     * @api {post} /user/waiting/countTeacherReservedLessons countTeacherReservedLessons()
14827     * @apiName countTeacherReservedLessons
14828     * @apiGroup Waiting
14829     * @apiDescription Counts the number of reserved lessons for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the reservation count.
14830     *
14831     * @apiBody {String} teacher_id The ID of the teacher.
14832     * 
14833     * @apiSuccess {Number} reservation_count The number of reserved lessons for the teacher.
14834     *
14835     * @apiSuccessExample {json} Success-Response:
14836     *     {
14837     *         "reservation_count": 5
14838     *     }
14839     *
14840     * @apiError {String} error Message indicating the error.
14841     *
14842     * @apiErrorExample {json} Error-Response:
14843     *     {
14844     *         "error": "Invalid request data."
14845     *     }
14846     * 
14847     * @apiSampleRequest off
14848     */
14849    public function countTeacherReservedLessons(){
14850        $this->autoRender = false;
14851        $this->layout = false;
14852        $reserveCount = array('reservation_count' => 0);
14853
14854        if ( $this->request->is('ajax') && !empty($this->request->data['teacher_id']) ) {
14855            $teacherId = $this->request->data['teacher_id'];
14856            $reserveCount['reservation_count'] = $this->LessonSchedule->countTeacherReservedLessons(array('teacherId' => $teacherId));
14857        }
14858        return json_encode($reserveCount);
14859    }
14860
14861    /**
14862     * Get Live coupon result for viewers
14863     * @param chathash
14864     * @param users_api_token
14865     * @return json
14866     */
14867    public function getLiveCouponResult()
14868    {
14869        $this->autoRender = false;
14870        $this->layout = false;
14871
14872        $users_api_token = $this->request->data['users_api_token'];
14873        $chat_hash = $this->request->data['chat_hash'];
14874        // open tunnel
14875        myTools::initializeApiTunnel(array('LessonDataController'));
14876
14877        // initialize controller
14878        $lcr = new LessonDataController();
14879
14880        // set data
14881        $lcr->params = [
14882            'nc_terminal_type' => 1,
14883            'chat_hash' => $chat_hash,
14884            'users_api_token' => $users_api_token
14885        ];
14886
14887        // process payment
14888        $response = json_decode($lcr->live_coupon_result(), true);
14889        return json_encode($response);    }
14890
14891    public function checkLessonStartButtonNormal() {
14892        $this->autoRender = false;
14893        $this->layout = false;
14894        $user = $this->sharedUserData;
14895        $data = $this->request->data;
14896        $response = [];
14897        $ua = myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) ?? '';
14898        $env = Configure::read('ENVIRONMENT');
14899
14900        if(empty($data['teacherId'])) {
14901            $response['error'] = 'Invalid parameters!';
14902            return json_encode($response);
14903        }
14904
14905        $studentId = (int) $data['studentId'];
14906        $teacherId = (int) $data['teacherId'];
14907        $counselingFlg = $data['counselingFlg'] ?? 0;
14908        myTools::initializeApiTunnel(array('TeachersDetailController'));
14909        $TeachersDetailController = new TeachersDetailController();
14910        $TeachersDetailController->params = [
14911            'nc_terminal_type' => 1, // pc
14912            'users_api_token' => $user['User']['api_token'],
14913            'teachers_id' => (int) $data['teacherId'],
14914            'la' => $data['la']
14915        ];    
14916        $api = json_decode($TeachersDetailController->detail(), true);        
14917
14918        if (json_last_error() !== JSON_ERROR_NONE) {
14919            $response['error'] = 'Failed to decode API response.';
14920            return json_encode($response);
14921        }
14922
14923        $isGuestViewer = empty($studentId) ? 1 : 0;
14924        $lessonStartBtnText = __d('waiting','今すぐレッスンへ進む');
14925        $lessonStartBtnTextBusy = __d('waiting','取り込み中');
14926        $lessonStartBtnText10minsRemaining = __d('waiting','レッスン終了まで あと%s分');
14927        $lessonOrangeButtonRemaining = false;
14928        $canLessonParam = array(
14929            'homeFlag' => isset($api['CommonTeacherStatus']['Teacher']['home_flg']) ? $api['CommonTeacherStatus']['Teacher']['home_flg'] : null,
14930            'isGuestViwer' => $isGuestViewer
14931        );    
14932        $canLesson = LessonOnairTable::canLesson($teacherId, $studentId, $canLessonParam);
14933        $liveDefault = (object)[
14934            'max_viewer' => Configure::read('max_live_lesson_viewer'),
14935            'lesson_flg' => 0,
14936            'lesson_joined' => 0,
14937            'lesson_started' => 0,
14938            'lesson_finish' => 0
14939        ];
14940        $liveData = isset($canLesson['liveLessonDetail']) && !empty($canLesson['liveLessonDetail']) ? $canLesson['liveLessonDetail'] : $liveDefault;        
14941        
14942        $loginDialog = [
14943            'headerMessage' => __d('login', 'ログインが必要です'),
14944            'message' => __d('login', 'こちらの機能は、ログイン後にご利用いただけます.'),
14945            'loginBtn' =>  __d('login', 'ログインはこちら'),
14946            'registerBtn' => __d('login', '新規会員登録はこちら')
14947        ];
14948        $json = [
14949            'lessonStartBtnText' => $lessonStartBtnText,
14950            'lessonStartBtnTextBusy' => $lessonStartBtnTextBusy,
14951            'lessonStartBtnText10minsRemaining' => $lessonStartBtnText10minsRemaining,
14952            'isGuestViewer' => (bool) $isGuestViewer,
14953            'loginDialog' => $loginDialog,
14954            'fullBaseUrl' => $this->baseUrl,
14955            'canLesson' => $canLesson
14956        ];
14957        $remainingLessonTime = 0;
14958        
14959        $canMidwayLesson = false;
14960        $isViewer = 0;
14961        $onair = $api['LessonOnair'];
14962        $hasRemainingLife = false;
14963        $unsupportedBrowser = false;
14964        $browser = $this->request->header('User-Agent');
14965
14966        if (preg_match('/(Edg|Edge)/i',$browser) ) {
14967            $unsupportedBrowser = false;
14968        } elseif (preg_match('/(OPR)/i',$browser)) {
14969            $unsupportedBrowser = true;
14970        } elseif (preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
14971            $unsupportedBrowser = false;
14972        } else {
14973            $unsupportedBrowser = true;
14974        }
14975
14976        $currentMin = date('i');
14977
14978        if (($currentMin >= 25 && $currentMin < 30) || ($currentMin >= 55 && $currentMin <= 59)) {
14979            $reservedId = isset($canLesson['nextReservation']['user_id']) ? $canLesson['nextReservation']['user_id'] : null;
14980        } else {
14981            $reservedId = isset($canLesson['currentReservation']['user_id']) ? $canLesson['currentReservation']['user_id'] : null;
14982        }
14983
14984        if(
14985            $liveData->lesson_flg && 
14986            (
14987                (
14988                    !is_null($onair['user_id']) &&
14989                    $onair['user_id'] == $studentId
14990                )
14991                ||
14992                (
14993                    is_null($onair['user_id']) &&
14994                    $reservedId &&
14995                    $reservedId != $studentId
14996                )
14997            )
14998        ) {
14999            $isViewer = 1;
15000        }
15001
15002        if(!$isGuestViewer) {        
15003            if(!empty($api['error'])) {
15004                $json['api_error'] = $api['error'];
15005                return json_encode($json);
15006            }
15007
15008            $buttonStates = array_flip(Configure::read('user_detail_state_button'));
15009            $stateButton = $api['teacher']['state_button'];
15010            $teacherStatusOnAir = $api['LessonOnair'] ?? null;
15011            $_teacherStatus = $api['TeacherStatus'];
15012            $reservedLessonData = $api['reservedLessonData'];
15013            $isReserved = $api['isReserved'];
15014            $teacher = $api['CommonTeacherStatus']['Teacher'];
15015            $remainingLessonTime = $api['remainingLessonTime'];
15016            $checkBadge = $api['checkBadge'];
15017            $teacherStatus = !empty($_teacherStatus) && empty($teacherStatusOnAir) ? $_teacherStatus : $teacherStatusOnAir;
15018            $_paymentPlanID = isset($user['User']['payment_plan_id']) ? $user['User']['payment_plan_id'] : null;
15019            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
15020            $stateButtonAddntlCheck = Configure::read('user_detail_state_button_addntl_check');
15021            $userNotEligible = false;
15022            $lessonType = false;
15023            $lessonOnOther = false;
15024            $lessonStartBtnText = $isNormalLitePlanUser ? __d('waiting','予約専用です') : __d('waiting','今すぐレッスンへ進む');
15025            $userDuplicateLesson = false;
15026            $isReservedCanSuddenLesson = false;
15027            $isReservedCanLessonViewing = false;
15028            $userAdminFlag = isset($user['User']['admin_flg']) ? $user['User']['admin_flg'] : '';
15029            $userFailFlag = isset($user['User']['fail_flg']) ? $user['User']['fail_flg'] : '';
15030            $userDoubleCheckFlag = isset($user['User']['double_check_flg']) ? $user['User']['double_check_flg']: '';
15031            $userCardCompany = isset($user['User']['card_company']) ? $user['User']['card_company']: '';
15032            $corporateUserFlg = isset($user['User']['corporate_id']) ? $user['User']['corporate_id'] : false;
15033            $isEmergencyLesson = (isset($data['emergencyFlg']) && $data['emergencyFlg']) ? true : false;
15034            $hasLessonBeforeActualTime = false;
15035            $teacherStatusColor = '';
15036            $ownReservationFlg = 0;
15037            $liveStatus = 0;
15038            $isBusy = false;
15039            $use7DaysTrialModal = false;
15040            $redirectPlanUrl = '';
15041            $teacherLeaveNotice = '';
15042            $showNativeSpeakerWarning = false;
15043            $baseUrl = myTools::getUrl($this->localizeDir);
15044
15045            // get reservation
15046            $nextReservation = LessonScheduleTable::getReservation(array(
15047                'LessonSchedule.teacher_id' => $api['CommonTeacherStatus']['Teacher']['id'],
15048                'LessonSchedule.user_id' => $data['studentId']
15049            ));
15050
15051            $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
15052            $queryCondition = array(
15053                'fields' => array(
15054                    'TeacherRankCoin.coins',
15055                    'TeacherRankCoin.reserve_coin_settings_flg',
15056                    'LessonOnair.id',
15057                    'LessonOnair.teacher_id',
15058                    'LessonOnair.user_id',
15059                    'TeacherRankCoin.limited_plan_reservation'
15060                ),
15061                'joins' => array(
15062                    array(
15063                        'type' => 'LEFT',
15064                        'table' => 'teacher_rank_coins',
15065                        'alias' => 'TeacherRankCoin',
15066                        'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
15067                    )
15068                ),
15069                'conditions' => array(
15070                    array('Teacher.id' => $teacher['id'])
15071                ),
15072                'show' => 'first'
15073            );
15074
15075            $commonTeacherStatusParams = array(
15076                'page_display' => 'listTeacher',
15077                'query_conditions' => $queryCondition
15078            );
15079
15080            $commonTeacher2 = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
15081            $loStatusParams = array(
15082                'LessonOnair' => $commonTeacher2['LessonOnair'],
15083                'Teacher' => $api['CommonTeacherStatus']['Teacher'],
15084                'TeacherStatus' => $api['CommonTeacherStatus']['TeacherStatus'],
15085                'nextReservation' => isset($nextReservation['teacher_id']) ? $nextReservation['teacher_id'] : null,
15086                'userId' => $studentId
15087            );
15088            $teacherStatusNew = LessonOnairTable::teacherStatusColor($loStatusParams);
15089            $teacherStatusColor = TeacherTable::teacherStatusCSS($teacherStatusNew);
15090            $sapuriCoin = $api['teacher']['sapuri_coin'];
15091
15092            if(empty($reservedLessonData)) {
15093                $this->LessonSchedule->recursive = 0;
15094                $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($studentId);
15095            }
15096
15097            // additional state button check from callLessonAlertandStartButton
15098            if(in_array($stateButton, $stateButtonAddntlCheck)) {
15099                // check if lessonOnair is empty
15100                if (isset($api['CommonTeacherStatus']['LessonOnair'])) {
15101                    $tmp = (object) $api['CommonTeacherStatus']['LessonOnair'];
15102                    if (!$tmp->id) {
15103                        $api['CommonTeacherStatus']['LessonOnair'] = null;
15104                    }
15105                }
15106                
15107                // check if lessonOnair contains empty values
15108                $oOnair = !empty($teacherStatus1) && empty($onair) 
15109                            ? new TeacherStatusTable($teacherStatus1) 
15110                            : $onair;    
15111
15112                //get next available schedule
15113                $checkNextSchedule = null;
15114                $checkScheduleCurrent = null;
15115                $lesson_time_stamp = floor(time() / (30 * 60)) * (30 * 60);
15116
15117                if(isset($canLesson['nextReserve'])) {
15118                    $nextSchedule = isset($canLesson['nextReserve']['start']) ? $canLesson['nextReserve']['start'] : null;
15119                    $checkNextSchedule = $nextSchedule ? $this->ShiftWorkOn->checkDataExist($teacherId , $nextSchedule) : null;
15120                    $checkScheduleCurrent = $this->ShiftWorkOn->checkDataExist( $teacherId , date('Y-m-d H:i:s',$lesson_time_stamp));
15121                }
15122
15123                $checkNextSchedule = !empty($checkNextSchedule) ? $checkNextSchedule : false;
15124                $checkScheduleCurrent = !empty($checkScheduleCurrent) ? $checkScheduleCurrent : false;
15125                $nextSchedule = isset($nextSchedule) ? $nextSchedule : '';
15126
15127                // add trappings for meal break, and change $canLesson['nextReserve']['start'] to mealbreak slot if has mealbreak
15128                if (
15129                    (($canLesson['lessonAvailable']
15130                    && !$checkNextSchedule 
15131                    && $checkScheduleCurrent)
15132                    || (isset($canLesson['hasMealbreakNext']) && $canLesson['hasMealbreakNext']))
15133                    && !($api['CommonTeacherStatus']['Teacher']['avatar_parent_flg'] == 1 || $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1)
15134                    && !$isEmergencyLesson  # ~don't show in emergency page
15135                    && !$this->isStudySapuriTosUser
15136                    && $api['CommonTeacherStatus']['Teacher']['home_flg'] != 1 // not home based teacher
15137                    && isset($exceedDailyLimit) && !empty($exceedDailyLimit) 
15138                ) {
15139                    $teacherLeaveNotice .= __d('waiting','こちらの講師は'). " ";
15140                    $teacherLeaveNotice .= isset($nextSchedule) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReserve']['start']), 'timestamp' => $this->timeDiffSecond, 'format' => 'h:i')) : '';
15141                    $teacherLeaveNotice .= " ". __d('waiting','までのレッスンとなりますので<br>ご了承ください。');
15142                }
15143
15144                // NJ-29831: check if user has reserved lesson for the next 5 min
15145                $scheduleReservationData = $this->LessonSchedule->getScheduledReservationNow($studentId, $teacherId);
15146                $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
15147                $hasLessonBeforeActualTime = false;
15148
15149                if (!empty($scheduleReservationData) && !$onGoingLesson) {
15150                    $hasLessonBeforeActualTime = true;
15151                    $isReserved = true;
15152                }
15153    
15154                //get preset textbook or last viewed
15155                $presetParams = array("user_id" => $studentId, 'userValidForSSBEDT' => $this->userValidForSSBEDT());
15156    
15157                //add additional parameter in fetching preset textbook
15158                if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
15159                    $presetParams["lang"] = $this->localizeDir;
15160                }
15161    
15162                $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
15163                if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
15164                    # for preset
15165                    $presetParams['connect_id'] = $preset_data['preset_connect_id'];
15166                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
15167    
15168                } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
15169                    # use last viewed textbook if no preset data.
15170                    $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
15171                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
15172                }
15173    
15174                // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
15175                $presetParams['is_pc_flg'] = 1;
15176    
15177                # fetch preset
15178                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
15179                if(!$preset) {
15180                    unset($presetParams['connect_id']);
15181                    unset($presetParams['last_opened_date']);
15182                    $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
15183                }
15184    
15185                $lessonData = $preset["textbook_info"];
15186                $categoryId = $lessonData["TextbookCategory"]["id"];
15187                $categoryTypeId = $lessonData["TextbookCategory"]["type_id"];
15188                $textbookId = $lessonData["Textbook"]["id"];
15189                
15190                if( $categoryTypeId == 1 ) { // course
15191                    $seriesId = $this->Textbook->getTextbookSeriesId(array( 'textbook_id' => $textbookId ));
15192                } else { // series
15193                    $seriesId = $categoryId;
15194                }
15195
15196                if(empty($checkBadge)) {
15197                    $checkBadge = $this->TeacherBadge->find("first", array(
15198                        "conditions" => array(
15199                            "TeacherBadge.teacher_id" => $teacherId,
15200                            "TeacherBadge.textbook_category_id" => $seriesId
15201                        ),
15202                        "fields" => array("TeacherBadge.id"),
15203                        "recursive" => -1
15204                    ));
15205                }
15206
15207                $canLessonTextbook = $checkBadge || $counselingFlg ? true : false;                
15208
15209                //check if the preset textbook is doesn't have reserve_flg
15210                $textbookForReservationOnly = isset($preset['reservation_flg']) ? $preset['reservation_flg'] : false;
15211                $uOnair = isset($onGoingLesson['LessonOnair']) ? $onGoingLesson['LessonOnair']: '';
15212                $browser =  $this->request->header('User-Agent');
15213                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
15214
15215                if ($uOnair != null) {
15216                    $uOOnair = new LessonOnairTable($uOnair);
15217                    //check user duplicate lesson
15218                    if ($uOOnair && $uOOnair->status == 3 && $uOOnair->user_id == $this->Auth->User('id') && $uOOnair->teacher_id != $teacherId) {
15219                        $userDuplicateLesson = true;
15220                        $lessonType = $uOOnair->lesson_type;
15221                    }
15222                    //check lesson on others
15223                    if ($oOnair && $oOnair->status == 3 && $oOnair->teacher_id == $teacherId && $oOnair->user_id != $studentId) {
15224                        $lessonOnOther = true;
15225                    }
15226                }
15227
15228                # - [NJ-18003] conditions for terminate reserved lesson for sudden lesson
15229                if (
15230                    $canLessonTextbook &&             # - can lesson with the textbook
15231                    !$textbookForReservationOnly && # - textbook not for reserve only
15232                    !$unsupportedBrowser &&         # - supported browser
15233                    $userDuplicateLesson &&         # - has lesson with other teacher
15234                    $lessonType == Configure::read('lesson.type.reservation') &&
15235                    !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
15236                    !$this->isStudySapuriUser &&    # - not sapuri user
15237                    ($uOnair && $uOnair['leave_lesson']) && # - already left the reserved lesson
15238                    !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
15239                    !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
15240                ) {
15241                    $isReservedCanSuddenLesson = true;
15242                }
15243
15244                // if failed settlement -> paid or corporate individual (standard/premium)
15245                if (in_array($this->userMembershipType, Configure::read('membership_type_credit_retry'))) {
15246                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_retry';
15247                // if free 
15248                } elseif ($this->userMembershipType == Configure::read('membership_type_plan_free')) {
15249                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_charge';
15250                // if free (trial not yet conducted)
15251                } elseif ($this->userMembershipType == 13) {
15252                    $userNotEligible = 10;
15253                    $use7DaysTrialModal = true;
15254                // if corporate company settlement failed -> standard/premium or
15255                } elseif (in_array($this->userMembershipType, Configure::read('membership_type_corporate_company_failed'))) {
15256                    $redirectPlanUrl = $baseUrl . '/account/contract_information';
15257                }
15258
15259                if( $teacherStatusNew == '5' ) {
15260                    $ownReservationFlg = 1;
15261                }
15262
15263                $membershipTypeReservationOnlyArr = Configure::read('membership_type_blue_btn_reservation_only');
15264                $membershipTypeReservationOnly = false;
15265
15266                if(in_array($this->userMembershipType, $membershipTypeReservationOnlyArr)) {
15267                    $membershipTypeReservationOnly = true;
15268                }
15269
15270                $membershipTypeBlueBtnArr = Configure::read('membership_type_blue_btn');
15271                $membershipTypeBlueBtn = false;
15272
15273                if(in_array($this->userMembershipType, $membershipTypeBlueBtnArr)) {
15274                    $teacherStatusColor = 'wait';
15275                    $membershipTypeBlueBtn = true;
15276                }
15277
15278                $liveLessonFlg = isset($commonTeacher2['LessonOnair']['live_lesson_flg']) ? $commonTeacher2['LessonOnair']['live_lesson_flg'] : 0;
15279
15280                if(!$isGuestViewer && $liveLessonFlg) {
15281                    $reservedLessonData = $api['reservedLessonData'];
15282
15283                    if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
15284                        $liveStatus = 0;
15285                    } else {
15286                        //- if lesson started
15287                        if (
15288                            !is_null($api['LessonOnair']['connect_id']) &&
15289                            !is_null($api['LessonOnair']['user_id'])
15290                        ) {
15291                            if ($api['LessonOnair']['user_id'] == $studentId) {
15292                                $liveStatus = 4;
15293                            } else {
15294                                //- check live status
15295                                $liveStatus = $this->LessonOnairsViewer->onGoingLiveStatus([
15296                                    'user_id' => $studentId,
15297                                    'chat_hash' => $api['LessonOnair']['chat_hash']
15298                                ]);
15299
15300                                //-- override status to watch
15301                                if ($liveStatus == 1) {
15302                                    $liveStatus = 2; //view live
15303                                }
15304                            }
15305                        } else {
15306                            $waitingReservationLive = $this->LessonSchedule->getWaitingLiveReservation([
15307                                'teacher_id' => $teacherId
15308                            ]);
15309
15310                            //-has reservation
15311                            if ($waitingReservationLive) {
15312                                if ($waitingReservationLive['LessonSchedule']['user_id'] == $studentId) {
15313                                    $liveStatus = (date('i') >= 0 && date('i') <= 26) || (date('i') >= 30 && date('i') <= 56) ? 4 : 0;
15314                                } else {
15315                                    $liveStatus = 1; //live will start
15316                                }
15317                            }
15318                        }
15319                    }
15320                }
15321
15322                if(!$this->isStudySapuriTosUser) {
15323                    $teacherStudentConnection = $api['teacherStudentConnection'];        
15324                    $teacherStudentData = isset($teacherStudentConnection['TeacherStudentConnection']) ? $teacherStudentConnection['TeacherStudentConnection'] : array();
15325                    if (isset($teacherStudentData['daily_lesson_minutes']) && $teacherStudentData['daily_lesson_minutes']) {
15326                        $exceedDailyLimit = $this->LessonOnair->lessonStartButton(array(
15327                            'teacher_id' => $teacherId,
15328                            'teacherStudentData' => $teacherStudentData,
15329                            'counseling_flg' => isset($commonTeacher2['Teacher']['counseling_flg']) ? $commonTeacher2['Teacher']['counseling_flg'] : 0,
15330                            'avatar_flg' => isset($commonTeacher2['Teacher']['avatar_flg']) ? $commonTeacher2['Teacher']['avatar_flg'] : 0,
15331                            'nickname' => $user['User']['nickname'],
15332                            'admin_flg' => $userAdminFlag,
15333                            'isReserved' => $isReserved,
15334                            'type' => 1
15335                        ));
15336                    }
15337                }
15338
15339                // check if busy
15340                if(isset($exceedDailyLimit) && $exceedDailyLimit && !$isReserved && !$liveData->lesson_flg && !$isGuestViewer) {
15341                    if(empty($teacherStatus->status) || (!empty($teacherStatus->status) && $teacherStatus->status == 1)) {
15342                        $isBusy = true;
15343                    }
15344                }
15345
15346                if(!$isGuestViewer && !isset($remainingLessonTime) || $remainingLessonTime <= 0 || $remainingLessonTime >= 660) {
15347                    $isBusy = true;
15348                }
15349
15350                // NC-5409 : Corporate Limited Plan
15351                if ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.limited') ) {
15352
15353                    // check if legible
15354                    if (
15355                        (    ($corporateType == Configure::read('corporate_type.limited') && !$isReserved) ||
15356                            (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
15357                            $userDuplicateLesson || 
15358                            $unsupportedBrowser ||
15359                            $lessonOnOther
15360                        ) &&
15361                        $studentId
15362                    ) {
15363                        $userNotEligible = 1;
15364                    }
15365
15366                } elseif ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.light') ) {
15367
15368                    $corpLightCondition1 = (
15369                        ($corporateType == Configure::read('corporate_type.light') && !$isReserved) ||
15370                        (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
15371                        $userDuplicateLesson ||
15372                        $unsupportedBrowser ||
15373                        $lessonOnOther
15374                    );
15375                    // check if legible
15376                    if ( $corpLightCondition1 && $studentId) {
15377                        $userNotEligible = 2;
15378                    }
15379                } elseif (
15380                    (
15381                        isset($commonTeacher2['Teacher']['native_speaker_flg']) &&
15382                        $commonTeacher2['Teacher']['native_speaker_flg']
15383                    ) &&
15384                    (
15385                        $user['User']['native_option'] == null ||
15386                        $user['User']['native_option'] == 0
15387                    ) &&
15388                    !$isReserved &&
15389                    !$tmp->live_lesson_flg &&
15390                    !$this->isStudySapuriTosUser
15391                ) {
15392                    $userNotEligible = 3;
15393                    $showNativeSpeakerWarning = true;
15394                } elseif ( // NJ-48797
15395                    (isset($getParentAvatarTeacher['Teacher']['native_speaker_flg']) && $getParentAvatarTeacher['Teacher']['native_speaker_flg']) &&
15396                    ($user['User']['native_option'] == null || $user['User']['native_option'] == 0) && 
15397                    !$isReserved &&
15398                    !$tmp->live_lesson_flg &&
15399                    !$this->isStudySapuriTosUser
15400                ) {
15401                    $showNativeSpeakerWarning = true;
15402                    $userNotEligible = 4;
15403                } else {
15404                    // check if legible
15405                    if ((
15406                        (!$isReserved && (!$canLessonTextbook ||$textbookForReservationOnly)) ||
15407                        $userDuplicateLesson || 
15408                        $unsupportedBrowser || 
15409                        (!$userAdminFlag && ($userFailFlag == 1 || $userDoubleCheckFlag == 2)) ||
15410                        $lessonOnOther
15411                    ) && $studentId) {
15412                        $userNotEligible = 5;
15413                    }
15414                }
15415
15416                # ~no sudden lesson for sapuri toS user
15417                if ($this->isStudySapuriTosUser && !$isReserved) {
15418                    $userNotEligible = 6;
15419                }
15420
15421                $_userReservedNowLesson = ($reservedLessonData && $reservedLessonData['Teacher']['id'] == $teacherId) ? true : false;
15422
15423                if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && !$_userReservedNowLesson && !$isEmergencyLesson) {
15424                    # disable the lesson button for lite plan if it is not reserved lesson
15425                    $userNotEligible = 7;
15426
15427                    # add if reserve is still ongoing 
15428                    if($isReserved) {
15429                        $userNotEligible = false;
15430                    }
15431                }
15432
15433            }            
15434
15435            switch($stateButton) {
15436                case 2: //proceed_to_the_lesson_immediately
15437                    if (!empty($api['CommonTeacherStatus']['user_id']) &&
15438                        $api['CommonTeacherStatus']['user_id'] != $user['id'] &&
15439                        in_array($api['CommonTeacherStatus']['TeacherStatus']['status'], [1, 3])
15440                    ) {
15441                        $stateButton = 5; //busy
15442                    }
15443                    break;
15444                case 3: // go to reserved lesson
15445                case 32: // dummy lesson
15446                    $teacherStatusColor = 'lesson';
15447                case 5: //busy
15448                    if( $teacherStatusColor == 'offline' && $membershipTypeReservationOnly ) {
15449                        $stateButton = 6;
15450                    }
15451                    $teacherStatusColor = 'lesson';
15452
15453                    break;
15454                default:
15455            }
15456
15457            $studentRemainingSecondsDelay = 0;
15458            $studentRemainingSecondsDelay = !empty($api['studentRemainingSecondsDelay']) ? $api['studentRemainingSecondsDelay'] : $studentRemainingSecondsDelay;
15459
15460            $showTakeBusinessTestModal = false;
15461            if (isset($user['User']['corporate_id'])) {
15462                $showTakeBusinessTestModal = false;
15463                $isTakenBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_flg'])) ? $user['User']['monthly_speaking_business_attended_flg'] : 0;
15464                $isMustTakeBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_must_flg'])) ? $user['User']['monthly_speaking_business_attended_must_flg'] : 0;
15465                $corporateUserDate = time();
15466                $twentyPlusDayOfTheMonth = strtotime(date('Y-m-20'));
15467
15468                if (
15469                    ($isTakenBusinessTestFlg == 0 && $isMustTakeBusinessTestFlg == 1) &&
15470                    !$isReserved &&
15471                    (
15472                        $corporateUserDate >= $twentyPlusDayOfTheMonth ||
15473                        (
15474                            $userAdminFlag == 1 ||
15475                            (
15476                                isset($user["User"]["nickname"]) &&
15477                                strpos(strtoupper($user["User"]["nickname"]), '%%%TEST%%%') !== false
15478                            )
15479                        )
15480                    )
15481                ) {
15482                    $showTakeBusinessTestModal = true;
15483                }
15484            }
15485
15486            // show orange button
15487            $lessonOrangeButtonRemaining = $this->triggerOrangeButton($studentId, $teacherId, $userNotEligible, $unsupportedBrowser, $canLesson['lessonAvailable']);
15488
15489            if (
15490                $canLessonTextbook &&             # - can lesson with the textbook
15491                !$textbookForReservationOnly && # - textbook not for reserve only
15492                !$unsupportedBrowser &&         # - supported browser
15493                $userDuplicateLesson &&         # - has lesson with other teacher
15494                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
15495                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
15496                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
15497            ) {
15498                $canMidwayLesson = true;
15499            }
15500        } else {
15501
15502        } //end $isGuestViewer
15503
15504        $isRedLamp = isset($data['redLamp']) && $data['redLamp'] == "1" ? true : false;
15505        $isRedLamp = (isset($teacherStatus['status']) && $teacherStatus['status'] == 5) ? true : $isRedLamp;
15506        $showLoader = $isGuestViewer ? true : false;    
15507        $suddenLessonFlg = false;
15508        $canDoLive = UserTable::canJoinLiveViewing($user['User']);        
15509
15510        if (
15511            $isReserved && 
15512            (
15513                $this->isStudySapuriUser || 
15514                $this->isStudySapuriTosUser || 
15515                in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')])
15516            )
15517        ) {
15518            $canDoLive = false;
15519        }
15520    
15521        if(
15522            !$isViewer && 
15523            !$isEmergencyLesson && 
15524            !$isReservedCanSuddenLesson & 
15525            !$canMidwayLesson &&
15526            !$isReserved
15527        ) {
15528            if($teacherStatusColor == 'wait') {
15529                if((!$canLessonTextbook && $this->isStudySapuriUser) || $membershipTypeReservationOnly) {
15530                    $isBusy = true;
15531                }
15532    
15533                if(!( !$canLessonTextbook && $this->isStudySapuriUser ) && !$membershipTypeReservationOnly) {
15534                    $suddenLessonFlg = true;
15535                }
15536            }
15537    
15538            if($teacherStatusColor == 'lesson' || $teacherStatusColor == 'offline') {
15539                if(!($unsupportedBrowser && $teacherStatusColor == 'lesson') || !$membershipTypeReservationOnly) {
15540                    
15541                    if($membershipTypeBlueBtn) {
15542                        $suddenLessonFlg = true;
15543                        $teacherStatusColor = 'wait';
15544                    }
15545                }
15546            }
15547        }
15548
15549        // set localize url
15550        if (
15551            isset($get['la']) && in_array($get['la'], array_flip(Configure::read('pc_allowed_currencies'))) &&
15552            $get['la'] != Configure::read('default.user_language')
15553        ) {
15554            $localizeUrl = myTools::getUrl() . '/' . $get['la'];
15555        } else {
15556            $localizeUrl = myTools::getUrl();
15557        }
15558
15559        $displayFamilyAlert = false;
15560        if (
15561            isset($this->sharedUserData['User']['parent_id']) &&
15562            !is_null($this->sharedUserData['User']['parent_id'])
15563        ) {
15564            $parent = $this->User->find('first', array(
15565                'fields' => array(
15566                    'User.id',
15567                    'User.hash16',
15568                    'User.charge_flg'
15569                ),
15570                'conditions' => array(
15571                    'User.id' => $this->sharedUserData['User']['parent_id']
15572                ),
15573                'recursive' => -1
15574            ));
15575
15576            if ($parent && $parent['User']['charge_flg'] != 1) {
15577                $displayFamilyAlert = true;
15578            }
15579        }
15580
15581        $device = false;
15582        if (strpos($ua, 'Silk') !== false) {
15583            $device = 'kindle';
15584        } else if (strpos($ua, 'Android') !== false) {
15585            $device = 'andriod';
15586        } else if (strpos($ua, 'iPhone') !== false) {
15587            $device = 'ios';
15588        } else if (strpos($ua, 'iPad') !== false) {
15589            $device = 'ios';
15590        } else if (strpos($ua, 'iPod') !== false) {
15591            $device = 'ios';
15592        } else {
15593            $device = 'pc';
15594        }
15595
15596        $liveLessonText = $liveData->lesson_flg ? __d('waiting','予約レッスン(LIVE)へ進む') : __d('waiting','予約レッスンへ進む');
15597        $button = $buttonStates[$stateButton];
15598        $canEmergencyLesson = false;
15599        $currentMinutes = date("i");
15600        $emergencyBreakTime = ['status' => false];
15601        $currentHour = date("H");
15602        
15603        if ($isEmergencyLesson) {
15604            if ($this->isStudySapuriTosUser) {
15605                $nextEmergencySlot = $this->LessonSchedule->getEmergencyTimeSlot();
15606                $nextReserveSlot = $this->LessonSchedule->getNextReservationTimeSlot();
15607                $queryCondition['fields'][] = "(
15608                    ((select smb.id from shift_work_meal_breaks as smb where smb.lesson_time >= '{$nextReserveSlot['start']}' and smb.lesson_time <= '{$nextReserveSlot['end']}' and smb.teacher_id = Teacher.id limit 1) IS NULL) AND 
15609                    ((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextEmergencySlot['start']}' and rs.lesson_time <= '{$nextEmergencySlot['end']}' and rs.status = 1 and rs.teacher_id = Teacher.id limit 1) IS NULL)
15610                    ) as can_emergency_lesson";
15611                $queryCondition['fields'][] = "((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextReserveSlot['start']}' and rs.lesson_time <= '{$nextReserveSlot['end']}' and rs.status = 1 and rs.user_id = {$studentId} limit 1) IS NULL) 
15612                    as student_no_next_reservation";
15613            }
15614
15615            $commonTeacherStatusParams = array(
15616                'page_display' => 'listTeacher',
15617                'query_conditions' => $queryCondition
15618            );
15619            $emergencyLessonOnair = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
15620            
15621            if (
15622                $this->isStudySapuriTosUser &&
15623                !$isReserved &&
15624                isset($emergencyLessonOnair[0]['can_emergency_lesson']) && 
15625                isset($emergencyLessonOnair[0]['student_no_next_reservation']) && 
15626                $emergencyLessonOnair[0]['can_emergency_lesson'] && # -can emergency
15627                $emergencyLessonOnair[0]['student_no_next_reservation']    # - no next reservation
15628            ) {
15629                $canEmergencyLesson = true;
15630            }
15631
15632            # ~if emergency lesson break time
15633            if ( !$isReserved && (($currentMinutes >= 26 && $currentMinutes <= 29) || ($currentMinutes >= 56 && $currentMinutes <= 59))) {
15634                $canEmergencyLesson = false;
15635                $emergencyBreakTime['status'] = true;
15636                $emergencyBreakTime['time_span'] = '['.$currentHour.'時26分 ~ '.$currentHour.'時30分]['.$currentHour.'時56分 ~ '.$currentHour.'時00分]';
15637                $emergencyBreakTime['time_return'] = '['.$currentHour.'時30分]['.$currentHour.'時00分]';
15638            }
15639        }        
15640
15641
15642        $isAvatar = $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 || $api['CommonTeacherStatus']['Teacher']['avatar_parent_flg'] == 1 ? true : false;
15643
15644        // lesson alert
15645        $lessonAlertMsg = [];
15646        $lessonAlertStatus = '';
15647
15648        // if emergency lesson break time
15649        if ($isEmergencyLesson && $emergencyBreakTime['status']) {
15650            $lessonAlertMsg = [
15651                ['text' => __d('waiting','しばらくお待ちください。')],
15652                ['text' => sprintf(__d('waiting','%sの間は緊急時予約レッスンにご入室いただけません。'), $emergencyBreakTime['time_span'])],
15653                ['text' => sprintf(__d('waiting','%sまでお待ちください。'), $emergencyBreakTime['time_return'])]
15654            ];
15655            $lessonAlertStatus = 'emergency_lesson_break_time';
15656        }
15657
15658        if (
15659            (isset($exceedDailyLimit) && $exceedDailyLimit) &&
15660            !$isReserved &&
15661            !$isAvatar
15662        ) {
15663            $lessonAlertMsg = [
15664                ['text' => __d('waiting','同一講師との連続した今すぐレッスンはレッスン完了から60分空けて再度受講が可能となります (講師の独占を緩和するため) 。')],
15665                ['text' => __d('waiting','※異なる講師を選択した場合は何度でも連続で今すぐレッスンの受講が可能です (今すぐレッスン回数無制限) 。')],
15666                ['text' => __d('waiting','※回線不具合等で短時間レッスンとなった場合は、レッスン合計時間が25分に達するまでの間は同一講師と連続で今すぐレッスンの受講が可能です。')]
15667            ];
15668            $lessonAlertStatus = 'exceed_daily_limit';
15669        }
15670
15671        $schedStartTime = isset($canLesson['nextReservation']['lesson_time']) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReservation']['lesson_time']), 'timestamp' => $this->timeDiffSecond, 'format' => 'H:i')) : '';
15672        $schedEndTime = isset($canLesson['possibleTime']) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['possibleTime']), 'timestamp' => $this->timeDiffSecond, 'format' => 'H:i')) : '';
15673
15674        if(
15675            isset($canLesson['possibleTime']) &&
15676            $canLesson['possibleTime'] !== false &&
15677            (!isset($isAvatar) || $isAvatar == false) &&
15678            $studentId &&
15679            !(isset($exceedDailyLimit) && $exceedDailyLimit) &&
15680            !$isEmergencyLesson
15681        ) {
15682            $canReserveLessonForReserved = 1;
15683        } else {
15684            $canReserveLessonForReserved = 0;
15685        }
15686
15687        if(
15688            isset($canLesson['possibleTime']) &&
15689            $canLesson['possibleTime'] !== false &&
15690            $isAvatar == false &&
15691            $studentId &&
15692            !(isset($exceedDailyLimit) && $exceedDailyLimit) &&
15693            !$this->isStudySapuriTosUser && !$isEmergencyLesson # ~don't show in emergency page
15694        ) {
15695            $lessonAlertStatus == 'lesson_reservation';
15696            $lessonAlertMsg = ['text' => sprintf(__d('waiting','この講師は、%1$s から予約が入っているため、%2$s までのレッスンとなります。ご了承の上レッスンへお進みください。'), $schedStartTime, $schedEndTime)];
15697        }
15698
15699        // user has reserved class (attempts to have a lesson with another teacher)
15700        if (
15701            $isAvatar == false && 
15702            $reservedLessonData && 
15703            (!$canLesson['lessonAvailable']) && !empty($teacherStatus) && ($teacherStatus->status == 1) && 
15704            (!empty($teacherStatus) && isset($teacherStatus->connect_flg) && $teacherStatus->connect_flg == 1 ) && 
15705            !$isReservedCanSuddenLesson
15706        ) {
15707            $lessonAlertStatus = 'reserved_class';
15708        }
15709
15710        $corporateIndividualUser = false;
15711        $corporateTypes = Configure::read('corporate_type_arr');
15712        $corporateTypeUserTable = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
15713        if (isset($user['User']['corporate_id'])) {
15714            $corporateAdminPaymentMethod = $this->Corporate->getPaymentMethod($user['User']['corporate_id']);
15715            $corporateIndividualUser = $corporateAdminPaymentMethod == 1 ? true : false;
15716        }
15717
15718        if (
15719            !$this->isStudySapuriUser &&
15720            $lessonType == Configure::read('lesson.type.reservation') &&
15721            ($uOnair && $uOnair['leave_lesson']) # - already left the reserved lesson
15722        ) {
15723            $isReservedCanLessonViewing = true;
15724        }
15725
15726        if(!$isGuestViewer) {
15727            $json = array_merge($json, [
15728                'apiStateButton' => $api['teacher']['state_button'],
15729                'button' => $button,
15730                'canDoLive' => $canDoLive,
15731                'canEmergencyLesson' => $canEmergencyLesson,
15732                'canLesson' => $canLesson,
15733                'canLessonTextbook' => $canLessonTextbook,
15734                'canMidwayLesson' => $canMidwayLesson,
15735                'canReserveLessonForReserved' => $canReserveLessonForReserved,
15736                'checkBadge' => $checkBadge,
15737                'corporateIndividualUser' => $corporateIndividualUser,
15738                'corporatePlanName' => isset($corporateTypeUserTable) ? (isset($corporateTypes[$corporateTypeUserTable]) ? $corporateTypes[$corporateTypeUserTable] : '') : '',
15739                'corporateType' => $corporateType,
15740                'corporateUserFlg' => $corporateUserFlg,
15741                'corpLightCondition' => $corpLightCondition1,
15742                'counselingFlg' => $counselingFlg,
15743                'device' => $device,
15744                'displayFamilyAlert' => $displayFamilyAlert,
15745                'dummyLessonRoom' => $hasLessonBeforeActualTime,
15746                'emergencyBreakTime' => $emergencyBreakTime,
15747                'exceedDailyLimit' => isset($exceedDailyLimit) ? $exceedDailyLimit : false,
15748                'hasLessonBeforeActualTime' => $hasLessonBeforeActualTime,
15749                'hasRemainingLife' => $hasRemainingLife,
15750                'homeFlg' => $api['CommonTeacherStatus']['Teacher']['home_flg'],
15751                'isAvatar' => $isAvatar,
15752                'isBusy' => $isBusy,
15753                'isEmergencyLesson' => $isEmergencyLesson,
15754                'isNormalLitePlanUser' => $isNormalLitePlanUser,
15755                'isRedLamp' => $isRedLamp,
15756                'isReserved' => $isReserved,
15757                'isReservedCanLessonViewing' => $isReservedCanLessonViewing,
15758                'isReservedCanSuddenLesson' => $isReservedCanSuddenLesson,
15759                'isStudySapuriTosUser' => $this->isStudySapuriUser,
15760                'isViewer' => $isViewer,
15761                'lessonAlertMsg' => $lessonAlertMsg,
15762                'lessonAlertStatus' => $lessonAlertStatus,
15763                'lessonOnAir' => $teacherStatusOnAir,
15764                'lessonOnOther' => $lessonOnOther,
15765                'lessonOrangeButtonRemaining' => $lessonOrangeButtonRemaining,
15766                'lessonType' => $lessonType,
15767                'liveData' => $liveData,
15768                'liveLessonFlg' => $liveLessonFlg ?? null,
15769                'liveLessonText' => $liveLessonText,
15770                'liveStatus' => $liveStatus,
15771                'localizeUrl' => $localizeUrl,
15772                'membershipTypeBlueBtn' => $membershipTypeBlueBtn,
15773                'membershipTypeReservationOnly' => $membershipTypeReservationOnly,
15774                'onair' => $onair,
15775                'uOnair' => $uOnair,
15776                'onGoingLesson' => $onGoingLesson,
15777                'ownReservationFlg' => $ownReservationFlg,
15778                'paymentPlanId' => $user['User']['payment_plan_id'],
15779                'points' => $this->UsersPoint->getCurrentUserPoint($studentId),
15780                'redirectPlanUrl' => $redirectPlanUrl,
15781                'remainingLessonTime' => (int) $remainingLessonTime,
15782                'reservedLessonData' => $reservedLessonData,
15783                'sapuriCoin' => $sapuriCoin,
15784                'scheduleReservationData' => $scheduleReservationData,
15785                'schedEndTime' => $schedEndTime,
15786                'schedStartTime' => $schedStartTime,
15787                'showLoader' => $showLoader,
15788                'showNativeSpeakerWarning' => $showNativeSpeakerWarning,
15789                'showTakeBusinessTestModal' => $showTakeBusinessTestModal,
15790                'stateButton' => $stateButton,
15791                'studentId' => $studentId,
15792                'suddenLessonFlg' => $suddenLessonFlg,
15793                'teacherAvatarFlg' => $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 ? true : false,
15794                'teacherLeaveNotice' => $teacherLeaveNotice,
15795                'teacherStatus' => $teacherStatus,
15796                'teacherStatusApi' => $_teacherStatus,
15797                'teacherStatusColor' => $teacherStatusColor,
15798                'textbookForReservationOnly' => (int)$textbookForReservationOnly,
15799                'unverifiedSMS' => $stateButton == 7 ? true : false,
15800                'unsupportedBrowser' => $unsupportedBrowser,
15801                'use7DaysTrialModal' => $use7DaysTrialModal,
15802                'userAdminFlag' => $userAdminFlag,
15803                'userDoubleCheckFlag' => $userDoubleCheckFlag,
15804                'userDuplicateLesson' => $userDuplicateLesson,
15805                'userFailFlag' => $userFailFlag,
15806                'userMembershipType' => $this->userMembershipType,
15807                'userNativeOption' => $user['User']['native_option'],
15808                'userNotEligible' => $userNotEligible
15809            ]);
15810
15811            if($membershipTypeReservationOnly) {
15812                $json['lessonStartBtnText'] = __d('waiting','予約専用です');
15813            }
15814
15815            if(
15816                $remainingLessonTime > 0 && 
15817                $remainingLessonTime < 660 &&
15818                !empty($teacherStatusOnAir['user_id']) && $teacherStatusOnAir['user_id'] != $studentId
15819            ) {
15820                $json['remainingLessonEndTime'] = $oOnair['end_time'];
15821
15822                if($remainingLessonTime <= 60) {
15823                    $json['lessonStartBtnText'] = __d('waiting', 'レッスン終了まで もうすぐ');
15824                } else {
15825                    $json['lessonStartBtnText'] = __d('waiting', 'レッスン終了まで あと%s分');
15826                }
15827            }
15828
15829            if($suddenLessonFlg) {
15830                if($use7DaysTrialModal) {
15831                    $json['suddenLessonStatus'] = 'use7DaysTrialModal';
15832                } else if (!empty(trim($redirectPlanUrl))) {
15833                    $json['suddenLessonStatus'] = 'redirectPlanUrl';
15834                } else if ($showNativeSpeakerWarning) {
15835                    $json['suddenLessonStatus'] = 'showNativeSpeakerWarning';
15836                } else if ($unsupportedBrowser) {
15837                    $json['suddenLessonStatus'] = 'unsupportedBrowser';
15838                } else if (!$canLessonTextbook) {
15839                    $json['suddenLessonStatus'] = 'cannotLessonTextbook';
15840                } else if (!empty($teacherLeaveNotice)) {
15841                    $json['suddenLessonStatus'] = 'teacherLeaveNotice';    
15842                }
15843
15844                if(!empty($json['suddenLessonStatus'])) {
15845                    $json['validateSuddenLessonFlg'] = false;
15846                } else {
15847                    $json['validateSuddenLessonFlg'] = true;
15848                }
15849            }
15850
15851        } else if ($isGuestViewer || $isViewer) {
15852            $json = array_merge($json, [
15853                'canLesson' => $canLesson,
15854                'isViewer' => $isViewer,
15855            ]);
15856        }
15857
15858        if($env != 'PRODUCTION') {
15859            $json['api'] = $api;
15860            $json['commonTeacher2'] = $commonTeacher2;
15861            $json['emergencyLessonOnair'] = $emergencyLessonOnair;
15862            $json['teacherStudentConnection'] = $api['teacherStudentConnection'];
15863            $json['tmpLessonOnAir'] = $tmp;
15864            $json['nextEmergencySlot'] = $nextEmergencySlot;
15865            $json['nextReserveSlot'] = $nextReserveSlot;
15866        }
15867
15868        return json_encode($json);
15869    }
15870
15871    public function checkLessonStartButtonAvatar() {
15872        $this->autoRender = false;
15873        $this->layout = false;
15874        $user = $this->sharedUserData;
15875        $data = $this->request->data;
15876        $response = [];
15877        $ua = myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) ?? '';
15878        $env = Configure::read('ENVIRONMENT');
15879    
15880        if(empty($data['teacherId'])) {
15881            $response['error'] = 'Invalid parameters!';
15882            return json_encode($response);
15883        }
15884    
15885        // if api token is not set
15886        if (empty($user['User']['api_token'])) {
15887            $userApiToken = $this->User->generateAndSaveApiToken($data['studentId']);
15888            $this->Session->write('Auth.User.api_token', $userApiToken);
15889        }
15890    
15891        $studentId = (int) $data['studentId'];
15892        $teacherId = (int) $data['teacherId'];
15893        $counselingFlg = $data['counselingFlg'] ?? 0;
15894        myTools::initializeApiTunnel(array('TeachersDetailController'));
15895        $TeachersDetailController = new TeachersDetailController();
15896        $TeachersDetailController->params = [
15897            'nc_terminal_type' => 1, // pc
15898            'users_api_token' => $user['User']['api_token'],
15899            'teachers_id' => (int) $data['teacherId'],
15900            'la' => $data['la']
15901        ];    
15902        $api = json_decode($TeachersDetailController->detail(), true);
15903
15904        if (json_last_error() !== JSON_ERROR_NONE) {
15905            $response['error'] = 'Failed to decode API response.';
15906            return json_encode($response);
15907        }
15908
15909        $isGuestViewer = empty($studentId) ? 1 : 0;
15910        $lessonStartBtnText = __d('waiting','今すぐレッスンへ進む');
15911        $lessonStartBtnTextBusy = __d('waiting','取り込み中');
15912        $lessonOrangeButtonRemaining = false;
15913        $loginDialog = [
15914            'headerMessage' => __d('login', 'ログインが必要です'),
15915            'message' => __d('login', 'こちらの機能は、ログイン後にご利用いただけます.'),
15916            'loginBtn' =>  __d('login', 'ログインはこちら'),
15917            'registerBtn' => __d('login', '新規会員登録はこちら')
15918        ];
15919        $json = [
15920            'lessonStartBtnText' => $lessonStartBtnText,
15921            'lessonStartBtnTextBusy' => $lessonStartBtnTextBusy,
15922            'isGuestViewer' => (bool) $isGuestViewer,
15923            'loginDialog' => $loginDialog,
15924            'fullBaseUrl' => $this->baseUrl,
15925        ];
15926        $canLessonParam = array(
15927            'homeFlag' => isset($api['teacher']['home_flg']) ? $api['teacher']['home_flg'] : null,
15928            'isGuestViwer' => $isGuestViewer
15929        );
15930        $canMidwayLesson = false;
15931        $canLesson = LessonOnairTable::canLesson($teacherId, $studentId, $canLessonParam);    
15932        $liveDefault = (object)[
15933            'max_viewer' => Configure::read('max_live_lesson_viewer'),
15934            'lesson_flg' => 0,
15935            'lesson_joined' => 0,
15936            'lesson_started' => 0,
15937            'lesson_finish' => 0
15938        ];
15939        $liveData = isset($canLesson['liveLessonDetail']) && !empty($canLesson['liveLessonDetail']) ? $canLesson['liveLessonDetail'] : $liveDefault;
15940        $currentMin = date('i');
15941        $isViewer = 0;
15942        $onair = $api['LessonOnair'];
15943        $hasRemainingLife = false;
15944        $unsupportedBrowser = false;
15945        $browser =  $this->request->header('User-Agent');
15946
15947        if (preg_match('/(Edg|Edge)/i',$browser) ) {
15948            $unsupportedBrowser = false;
15949        } elseif (preg_match('/(OPR)/i',$browser)) {
15950            $unsupportedBrowser = true;
15951        } elseif (preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
15952            $unsupportedBrowser = false;
15953        } else {
15954            $unsupportedBrowser = true;
15955        }
15956
15957        if (($currentMin >= 25 && $currentMin < 30) || ($currentMin >= 55 && $currentMin <= 59)) {
15958            $reservedId = isset($canLesson['nextReservation']['user_id']) ? $canLesson['nextReservation']['user_id'] : null;
15959        } else {
15960            $reservedId = isset($canLesson['currentReservation']['user_id']) ? $canLesson['currentReservation']['user_id'] : null;
15961        }
15962
15963        if(
15964            $liveData->lesson_flg && 
15965            (
15966                (
15967                    !is_null($onair['user_id']) &&
15968                    $onair['user_id'] == $studentId
15969                )
15970                ||
15971                (
15972                    is_null($onair['user_id']) &&
15973                    $reservedId &&
15974                    $reservedId != $studentId
15975                )
15976            )
15977        ) {
15978            $isViewer = 1;
15979        }
15980
15981        $isGuestViewer = (empty($studentId) && $isViewer) ? 1 : 0;
15982    
15983        if(!$isGuestViewer) {
15984            if(!empty($api['error'])) {
15985                $json['api_error'] = $api['error'];
15986                return json_encode($json);
15987            }
15988    
15989            $buttonStates = array_flip(Configure::read('user_detail_state_button'));
15990            $stateButton = $api['teacher']['state_button'];
15991            $teacherStatusOnAir = $api['LessonOnair'] ?? null;
15992            $_teacherStatus = $api['TeacherStatus'];
15993            $reservedLessonData = $api['reservedLessonData'];
15994            $isReserved = $api['isReserved'];
15995            $teacher = $api['CommonTeacher`Status']['Teacher'];
15996            $checkBadge = $api['checkBadge'];
15997            $teacherStatus = !empty($_teacherStatus) && empty($teacherStatusOnAir) ? $_teacherStatus : $teacherStatusOnAir;
15998            $_paymentPlanID = isset($user['User']['payment_plan_id']) ? $user['User']['payment_plan_id'] : null;
15999            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
16000            $stateButtonAddntlCheck = Configure::read('user_detail_state_button_addntl_check');
16001            $userNotEligible = false;
16002            $lessonType = false;
16003            $lessonOnOther = false;
16004            $lessonStartBtnText = $isNormalLitePlanUser ? __d('waiting','予約専用です') : __d('waiting','今すぐレッスンへ進む');
16005            $userDuplicateLesson = false;
16006            $isReservedCanSuddenLesson = false;
16007            $isReservedCanLessonViewing = false;
16008            $userAdminFlag = isset($user['User']['admin_flg']) ? $user['User']['admin_flg'] : '';
16009            $userFailFlag = isset($user['User']['fail_flg']) ? $user['User']['fail_flg'] : '';
16010            $userDoubleCheckFlag = isset($user['User']['double_check_flg']) ? $user['User']['double_check_flg']: '';
16011            $userCardCompany = isset($user['User']['card_company']) ? $user['User']['card_company']: '';
16012            $corporateUserFlg = isset($user['User']['corporate_id']) ? $user['User']['corporate_id'] : false;
16013            $isEmergencyLesson = (isset($data['emergencyFlg']) && $data['emergencyFlg']) ? true : false;
16014            $hasLessonBeforeActualTime = false;
16015            $teacherStatusColor = '';
16016            $ownReservationFlg = 0;
16017            $liveStatus = 0;
16018            $isBusy = false;
16019            $use7DaysTrialModal = false;
16020            $redirectPlanUrl = '';
16021            $teacherLeaveNotice = '';
16022            $showNativeSpeakerWarning = false;
16023            $baseUrl = myTools::getUrl($this->localizeDir);                
16024            
16025            // get reservation
16026            $nextReservation = LessonScheduleTable::getReservation(array(
16027                'LessonSchedule.teacher_id' => $api['CommonTeacherStatus']['Teacher']['id'],
16028                'LessonSchedule.user_id' => $data['studentId']
16029            ));
16030
16031            $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
16032            $queryCondition = array(
16033                'fields' => array(
16034                        'TeacherRankCoin.coins',
16035                        'TeacherRankCoin.reserve_coin_settings_flg',
16036                        'LessonOnair.id',
16037                        'LessonOnair.teacher_id',
16038                        'LessonOnair.user_id',
16039                        'TeacherRankCoin.limited_plan_reservation'
16040                    ),
16041                'joins' => array(
16042                    array(
16043                        'type' => 'LEFT',
16044                        'table' => 'teacher_rank_coins',
16045                        'alias' => 'TeacherRankCoin',
16046                        'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
16047                    )
16048                ),
16049                'conditions' => array(
16050                    array('Teacher.id' => $teacherId)
16051                ),
16052                'show' => 'first'
16053            );
16054
16055            $commonTeacherStatusParams = array(
16056                'page_display' => 'listTeacher',
16057                'query_conditions' => $queryCondition
16058            );
16059
16060            $commonTeacher2 = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
16061            $loStatusParams = array(
16062                'LessonOnair' => $commonTeacher2['LessonOnair'],
16063                'Teacher' => $api['CommonTeacherStatus']['Teacher'],
16064                'TeacherStatus' => $api['CommonTeacherStatus']['TeacherStatus'],
16065                'nextReservation' => isset($nextReservation['teacher_id']) ? $nextReservation['teacher_id'] : null,
16066                'userId' => $studentId
16067            );
16068            $teacherStatusNew = LessonOnairTable::teacherStatusColor($loStatusParams);
16069            $teacherParams = array(
16070                    'type' => 'first',
16071                    'args' => array(
16072                        'conditions' => array(
16073                            'id' => $teacherId
16074                        ),
16075                        'recursive' => -1
16076                    )
16077                );
16078            $teacherInfo = $this->Teacher->getTeachers($teacherParams);
16079
16080            if (
16081                ($teacher['avatar_id'] &&
16082                $teacherStatus['status'] == 4)
16083            ) {
16084                $teacherStatusNew = 3;
16085            }
16086
16087            if(empty($reservedLessonData)) {
16088                $this->LessonSchedule->recursive = 0;
16089                $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($studentId);
16090            }
16091
16092            $teacherStatusColor = TeacherTable::teacherStatusCSS($teacherStatusNew);
16093            $sapuriCoin = $api['teacher']['sapuri_coin'];
16094    
16095            // additional state button check from callLessonAlertandStartButton
16096            if(in_array($stateButton, $stateButtonAddntlCheck)) {
16097                // check if lessonOnair is empty
16098                if (isset($api['CommonTeacherStatus']['LessonOnair'])) {
16099                    $tmp = (object) $api['CommonTeacherStatus']['LessonOnair'];
16100                    if (!$tmp->id) {
16101                        $api['CommonTeacherStatus']['LessonOnair'] = null;
16102                    }
16103                }
16104    
16105                // check if lessonOnair contains empty values
16106                $oOnair = !empty($teacherStatus1) && empty($onair) 
16107                            ? new TeacherStatusTable($teacherStatus1)
16108                            : $onair;
16109    
16110                //get next available schedule
16111                $checkNextSchedule = null;
16112                $checkScheduleCurrent = null;
16113                $lesson_time_stamp = floor(time() / (30 * 60)) * (30 * 60);
16114    
16115                if(isset($canLesson['nextReserve'])) {
16116                    $nextSchedule = isset($canLesson['nextReserve']['start']) ? $canLesson['nextReserve']['start'] : null;
16117                    $checkNextSchedule = $nextSchedule ? $this->ShiftWorkOn->checkDataExist($teacherId , $nextSchedule) : null;
16118                    $checkScheduleCurrent = $this->ShiftWorkOn->checkDataExist( $teacherId , date('Y-m-d H:i:s',$lesson_time_stamp));
16119                }
16120    
16121                $checkNextSchedule = !empty($checkNextSchedule) ? $checkNextSchedule : false;
16122                $checkScheduleCurrent = !empty($checkScheduleCurrent) ? $checkScheduleCurrent : false;
16123                $nextSchedule = isset($nextSchedule) ? $nextSchedule : '';
16124    
16125                // add trappings for meal break, and change $canLesson['nextReserve']['start'] to mealbreak slot if has mealbreak
16126                if (
16127                    (($canLesson['lessonAvailable']
16128                    && !$checkNextSchedule 
16129                    && $checkScheduleCurrent)
16130                    || (isset($canLesson['hasMealbreakNext']) && $canLesson['hasMealbreakNext']))
16131                    && !($teacherInfo['Teacher']['avatar_parent_flg'] == 1 || $teacherInfo['Teacher']['avatar_flg'] == 1)
16132                    && !$isEmergencyLesson  # ~don't show in emergency page
16133                    && !$this->isStudySapuriTosUser
16134                    && $teacherInfo['Teacher']['home_flg'] != 1 // not home based teacher
16135                    && isset($exceedDailyLimit) && !empty($exceedDailyLimit) 
16136                ) {
16137                    $teacherLeaveNotice .= __d('waiting','こちらの講師は'). " ";
16138                    $teacherLeaveNotice .= isset($nextSchedule) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReserve']['start']), 'timestamp' => $this->timeDiffSecond, 'format' => 'h:i')) : '';
16139                    $teacherLeaveNotice .= " ". __d('waiting','までのレッスンとなりますので<br>ご了承ください。');
16140                }
16141    
16142                // NJ-29831: check if user has reserved lesson for the next 5 min
16143                $scheduleReservationData = $this->LessonSchedule->getScheduledReservationNow($studentId, $teacherInfo['Teacher']['id']);
16144                $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
16145                $hasLessonBeforeActualTime = false;
16146    
16147                if (!empty($scheduleReservationData) && !$onGoingLesson) {
16148                    $hasLessonBeforeActualTime = true;
16149                    $isReserved = true;
16150                }
16151    
16152                //get preset textbook or last viewed
16153                $presetParams = array("user_id" => $studentId, 'userValidForSSBEDT' => $this->userValidForSSBEDT());
16154    
16155                //add additional parameter in fetching preset textbook
16156                if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
16157                    $presetParams["lang"] = $this->localizeDir;
16158                }
16159    
16160                $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
16161                if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
16162                    # for preset
16163                    $presetParams['connect_id'] = $preset_data['preset_connect_id'];
16164                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
16165    
16166                } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
16167                    # use last viewed textbook if no preset data.
16168                    $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
16169                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
16170                }
16171    
16172                // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
16173                $presetParams['is_pc_flg'] = 1;
16174    
16175                # fetch preset
16176                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
16177                if(!$preset) {
16178                    unset($presetParams['connect_id']);
16179                    unset($presetParams['last_opened_date']);
16180                    $preset = $this->UsersTextbookInfo->getTextbookInfos($presetParams);
16181                }
16182    
16183                $lessonData = $preset["textbook_info"];
16184                $categoryId = $lessonData["TextbookCategory"]["id"];
16185                $categoryTypeId = $lessonData["TextbookCategory"]["type_id"];
16186                $textbookId = $lessonData["Textbook"]["id"];
16187                
16188                if( $categoryTypeId == 1 ) { // course
16189                    $seriesId = $this->Textbook->getTextbookSeriesId(array( 'textbook_id' => $textbookId ));
16190                } else { // series
16191                    $seriesId = $categoryId;
16192                }
16193
16194                if(empty($checkBadge)) {
16195                    $checkBadge = $this->TeacherBadge->find("first", array(
16196                        "conditions" => array(
16197                            "TeacherBadge.teacher_id" => $teacherId,
16198                            "TeacherBadge.textbook_category_id" => $seriesId
16199                        ),
16200                        "fields" => array("TeacherBadge.id"),
16201                        "recursive" => -1
16202                    ));
16203                }
16204    
16205                $canLessonTextbook = $checkBadge || $counselingFlg ? true : false;                
16206    
16207                //check if the preset textbook is doesn't have reserve_flg
16208                $textbookForReservationOnly = isset($preset['reservation_flg']) ? $preset['reservation_flg'] : false;
16209                $uOnair = isset($onGoingLesson['LessonOnair']) ? $onGoingLesson['LessonOnair']: '';
16210                
16211                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
16212    
16213                if ($uOnair != null) {
16214                    $uOOnair = new LessonOnairTable($uOnair);
16215                    //check user duplicate lesson
16216                    if ($uOOnair && $uOOnair->status == 3 && $uOOnair->user_id == $this->Auth->User('id') && $uOOnair->teacher_id != $teacherId) {
16217                        $userDuplicateLesson = true;
16218                        $lessonType = $uOOnair->lesson_type;
16219                    }
16220                    //check lesson on others
16221                    if ($oOnair && $oOnair->status == 3 && $oOnair->teacher_id == $teacherId && $oOnair->user_id != $studentId) {
16222                        $lessonOnOther = true;
16223                    }
16224                }
16225    
16226                # - [NJ-18003] conditions for terminate reserved lesson for sudden lesson
16227                if (
16228                    $canLessonTextbook &&             # - can lesson with the textbook
16229                    !$textbookForReservationOnly && # - textbook not for reserve only
16230                    !$unsupportedBrowser &&         # - supported browser
16231                    $userDuplicateLesson &&         # - has lesson with other teacher
16232                    $lessonType == Configure::read('lesson.type.reservation') &&
16233                    !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
16234                    !$this->isStudySapuriUser &&    # - not sapuri user
16235                    ($uOnair && $uOnair['leave_lesson']) && # - already left the reserved lesson
16236                    !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
16237                    !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
16238                ) {
16239                    $isReservedCanSuddenLesson = true;
16240                }
16241    
16242                // if failed settlement -> paid or corporate individual (standard/premium)
16243                if (in_array($this->userMembershipType, Configure::read('membership_type_credit_retry'))) {
16244                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_retry';
16245                // if free 
16246                } elseif ($this->userMembershipType == Configure::read('membership_type_plan_free')) {
16247                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_charge';
16248                // if free (trial not yet conducted)
16249                } elseif ($this->userMembershipType == 13) {
16250                    $userNotEligible = 10;
16251                    $use7DaysTrialModal = true;
16252                // if corporate company settlement failed -> standard/premium or
16253                } elseif (in_array($this->userMembershipType, Configure::read('membership_type_corporate_company_failed'))) {
16254                    $redirectPlanUrl = $baseUrl . '/account/contract_information';
16255                }
16256
16257                // NJ-48797
16258                $avatarParentFlg = isset($commonTeacher2['Teacher']['avatar_parent_flg']) && $commonTeacher2['Teacher']['avatar_parent_flg'] == 1;
16259
16260                if (!$avatarParentFlg) {
16261                    $getParentAvatarTeacher = $this->Teacher->find('first', array(
16262                        'fields' => array('Teacher.id', 'Teacher.native_speaker_flg'),
16263                        'conditions' => array(
16264                            'Teacher.id' => $commonTeacher2['Teacher']['avatar_id'],
16265                            'Teacher.avatar_parent_flg' => 1
16266                        ),
16267                        'recursive' => -1
16268                    ));
16269                } else {
16270                    $getParentAvatarTeacher = $commonTeacher2;
16271                }
16272                
16273                $membershipTypeReservationOnlyArr = Configure::read('membership_type_blue_btn_reservation_only');
16274                $membershipTypeReservationOnly = false;
16275    
16276                if(in_array($this->userMembershipType, $membershipTypeReservationOnlyArr)) {
16277                    $membershipTypeReservationOnly = true;
16278                }
16279    
16280                $membershipTypeBlueBtnArr = Configure::read('membership_type_blue_btn');
16281                $membershipTypeBlueBtn = false;
16282    
16283                if(in_array($this->userMembershipType, $membershipTypeBlueBtnArr)) {
16284                    $teacherStatusColor = 'wait';
16285                    $membershipTypeBlueBtn = true;
16286                }
16287    
16288                $liveLessonFlg = isset($commonTeacher2['LessonOnair']['live_lesson_flg']) ? $commonTeacher2['LessonOnair']['live_lesson_flg'] : 0;
16289    
16290                if(!$isGuestViewer && $liveLessonFlg) {
16291                    $reservedLessonData = $api['reservedLessonData'];
16292    
16293                    if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
16294                        $liveStatus = 0;
16295                    } else {
16296                        //- if lesson started
16297                        if (
16298                            !is_null($api['LessonOnair']['connect_id']) &&
16299                            !is_null($api['LessonOnair']['user_id'])
16300                        ) {
16301                            if ($api['LessonOnair']['user_id'] == $studentId) {
16302                                $liveStatus = 4;
16303                            } else {
16304                                //- check live status
16305                                $liveStatus = $this->LessonOnairsViewer->onGoingLiveStatus([
16306                                    'user_id' => $studentId,
16307                                    'chat_hash' => $api['LessonOnair']['chat_hash']
16308                                ]);
16309    
16310                                //-- override status to watch
16311                                if ($liveStatus == 1) {
16312                                    $liveStatus = 2; //view live
16313                                }
16314                            }
16315                        } else {
16316                            $waitingReservationLive = $this->LessonSchedule->getWaitingLiveReservation([
16317                                'teacher_id' => $teacherId
16318                            ]);
16319    
16320                            //-has reservation
16321                            if ($waitingReservationLive) {
16322                                if ($waitingReservationLive['LessonSchedule']['user_id'] == $studentId) {
16323                                    $liveStatus = (date('i') >= 0 && date('i') <= 26) || (date('i') >= 30 && date('i') <= 56) ? 4 : 0;
16324                                } else {
16325                                    $liveStatus = 1; //live will start
16326                                }
16327                            }
16328                        }
16329                    }
16330                }
16331    
16332                if(!$this->isStudySapuriTosUser) {
16333                    $teacherStudentConnection = $api['teacherStudentConnection'];        
16334                    $teacherStudentData = isset($teacherStudentConnection['TeacherStudentConnection']) ? $teacherStudentConnection['TeacherStudentConnection'] : array();
16335                    if (isset($teacherStudentData['daily_lesson_minutes']) && $teacherStudentData['daily_lesson_minutes']) {
16336                        $exceedDailyLimit = $this->LessonOnair->lessonStartButton(array(
16337                            'teacher_id' => $teacherId,
16338                            'teacherStudentData' => $teacherStudentData,
16339                            'counseling_flg' => isset($commonTeacher2['Teacher']['counseling_flg']) ? $commonTeacher2['Teacher']['counseling_flg'] : 0,
16340                            'avatar_flg' => isset($commonTeacher2['Teacher']['avatar_flg']) ? $commonTeacher2['Teacher']['avatar_flg'] : 0,
16341                            'nickname' => $user['User']['nickname'],
16342                            'admin_flg' => $userAdminFlag,
16343                            'isReserved' => $isReserved,
16344                            'type' => 1
16345                        ));
16346                    }
16347                }
16348    
16349                // check if busy
16350                if(isset($exceedDailyLimit) && $exceedDailyLimit && !$isReserved && !$liveData->lesson_flg && !$isGuestViewer) {
16351                    if(empty($teacherStatus->status) || (!empty($teacherStatus->status) && $teacherStatus->status == 1)) {
16352                        $isBusy = true;
16353                    }
16354                }
16355    
16356                // NC-5409 : Corporate Limited Plan
16357                if ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.limited') ) {
16358    
16359                    // check if legible
16360                    if (
16361                        (    ($corporateType == Configure::read('corporate_type.limited') && !$isReserved) ||
16362                            (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
16363                            $userDuplicateLesson || 
16364                            $unsupportedBrowser ||
16365                            $lessonOnOther
16366                        ) &&
16367                        $studentId
16368                    ) {
16369                        $userNotEligible = 1;
16370                    }
16371    
16372                } elseif ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.light') ) {
16373    
16374                    $corpLightCondition1 = (
16375                        ($corporateType == Configure::read('corporate_type.light') && !$isReserved) ||
16376                        (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
16377                        $userDuplicateLesson ||
16378                        $unsupportedBrowser ||
16379                        $lessonOnOther
16380                    );
16381                    // check if legible
16382                    if ( $corpLightCondition1 && $studentId) {
16383                        $userNotEligible = 2;
16384                    }
16385                } elseif (
16386                    (
16387                        isset($commonTeacher2['Teacher']['native_speaker_flg']) &&
16388                        $commonTeacher2['Teacher']['native_speaker_flg']
16389                    ) &&
16390                    (
16391                        $user['User']['native_option'] == null ||
16392                        $user['User']['native_option'] == 0
16393                    ) &&
16394                    !$isReserved &&
16395                    !$tmp->live_lesson_flg &&
16396                    !$this->isStudySapuriTosUser
16397                ) {
16398                    $userNotEligible = 3;
16399                    $showNativeSpeakerWarning = true;
16400                } elseif ( // NJ-48797
16401                    (isset($getParentAvatarTeacher['Teacher']['native_speaker_flg']) && $getParentAvatarTeacher['Teacher']['native_speaker_flg']) &&
16402                    ($user['User']['native_option'] == null || $user['User']['native_option'] == 0) && 
16403                    !$isReserved &&
16404                    !$tmp->live_lesson_flg &&
16405                    !$this->isStudySapuriTosUser
16406                ) {
16407                    $showNativeSpeakerWarning = true;
16408                    $userNotEligible = 4;
16409                } else {
16410                    // check if legible
16411                    if ((
16412                        (!$isReserved && (!$canLessonTextbook ||$textbookForReservationOnly)) ||
16413                        $userDuplicateLesson || 
16414                        $unsupportedBrowser || 
16415                        (!$userAdminFlag && ($userFailFlag == 1 || $userDoubleCheckFlag == 2)) ||
16416                        $lessonOnOther
16417                    ) && $studentId) {
16418                        $userNotEligible = 5;
16419                    }
16420                }
16421    
16422                # ~no sudden lesson for sapuri toS user
16423                if ($this->isStudySapuriTosUser && !$isReserved) {
16424                    $userNotEligible = 6;
16425                }
16426    
16427                $_userReservedNowLesson = ($reservedLessonData && $reservedLessonData['Teacher']['id'] == $teacherId) ? true : false;
16428    
16429                if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && !$_userReservedNowLesson && !$isEmergencyLesson) {
16430                    # disable the lesson button for lite plan if it is not reserved lesson
16431                    $userNotEligible = 7;
16432    
16433                    # add if reserve is still ongoing 
16434                    if($isReserved) {
16435                        $userNotEligible = false;
16436                    }
16437                }
16438    
16439            }            
16440    
16441            switch($stateButton) {
16442                case 2: //proceed_to_the_lesson_immediately
16443                    if (!empty($api['CommonTeacherStatus']['user_id']) &&
16444                        $api['CommonTeacherStatus']['user_id'] != $user['id'] &&
16445                        in_array($api['CommonTeacherStatus']['TeacherStatus']['status'], [1, 3])
16446                    ) {
16447                        $stateButton = 5; //busy
16448                    }
16449                    break;
16450                case 3: // go to reserved lesson
16451                case 32: // dummy lesson
16452                    $teacherStatusColor = 'wait';
16453                    break;
16454                case 15: //other
16455                case 5: //busy
16456                    if(
16457                        ($teacherStatusColor == 'lesson' || $teacherStatusColor == 'offline') &&
16458                        $membershipTypeReservationOnly
16459                    ) {
16460                        $stateButton = 6;
16461                        $lessonStartBtnText = __d('waiting','予約専用です');
16462                    }
16463                    $teacherStatusColor = 'lesson';
16464    
16465                    break;
16466                default:
16467            }
16468
16469            $studentRemainingSecondsDelay = 0;
16470            $studentRemainingSecondsDelay = !empty($api['studentRemainingSecondsDelay']) ? $api['studentRemainingSecondsDelay'] : $studentRemainingSecondsDelay;
16471    
16472            // show orange button
16473            $lessonOrangeButtonRemaining = $this->triggerOrangeButton($this->Auth->User('id'), $teacherId, $userNotEligible, $unsupportedBrowser, $canLesson['lessonAvailable']);
16474
16475            if (
16476                $canLessonTextbook &&             # - can lesson with the textbook
16477                !$textbookForReservationOnly && # - textbook not for reserve only
16478                !$unsupportedBrowser &&         # - supported browser
16479                $userDuplicateLesson &&         # - has lesson with other teacher
16480                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
16481                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
16482                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
16483            ) {
16484                $canMidwayLesson = true;
16485            }
16486        } //end !$isGuestViewer
16487    
16488        $isRedLamp = isset($data['redLamp']) && $data['redLamp'] == "1" ? true : false;
16489        $isRedLamp = (isset($teacherStatus['status']) && $teacherStatus['status'] == 5) ? true : $isRedLamp;
16490        $showLoader = $isGuestViewer ? true : false;    
16491        $suddenLessonFlg = false;
16492        $canDoLive = UserTable::canJoinLiveViewing($user['User']);
16493    
16494        if (
16495            $isReserved && 
16496            (
16497                $this->isStudySapuriUser || 
16498                $this->isStudySapuriTosUser || 
16499                in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')])
16500            )
16501        ) {
16502            $canDoLive = false;
16503        }
16504    
16505        if(
16506            !$isViewer && 
16507            !$isEmergencyLesson && 
16508            !$isReservedCanSuddenLesson & 
16509            !$canMidwayLesson &&
16510            !$isReserved
16511        ) {
16512            if($teacherStatusColor == 'wait') {
16513                if((!$canLessonTextbook && $this->isStudySapuriUser) || $membershipTypeReservationOnly) {
16514                    $isBusy = true;
16515                }
16516    
16517                if(!( !$canLessonTextbook && $this->isStudySapuriUser ) && !$membershipTypeReservationOnly) {
16518                    $suddenLessonFlg = true;
16519                }
16520            }
16521    
16522            if($teacherStatusColor == 'lesson' || $teacherStatusColor == 'offline') {
16523                if(!($unsupportedBrowser && $teacherStatusColor == 'lesson') || !$membershipTypeReservationOnly) {
16524                    
16525                    if($membershipTypeBlueBtn) {
16526                        $suddenLessonFlg = true;
16527                        $teacherStatusColor = 'wait';
16528                    }
16529                }
16530            }
16531        }
16532    
16533        $canEmergencyLesson = false;
16534        $emergencyBreakTime = ['status' => false];        
16535        $currentMinutes = date("i");
16536        $currentHour = date("H");        
16537
16538        if ($isEmergencyLesson) {
16539            if ($this->isStudySapuriTosUser) {
16540                $nextEmergencySlot = $this->LessonSchedule->getEmergencyTimeSlot();
16541                $nextReserveSlot = $this->LessonSchedule->getNextReservationTimeSlot();
16542                $queryCondition['fields'][] = "(
16543                    ((select smb.id from shift_work_meal_breaks as smb where smb.lesson_time >= '{$nextReserveSlot['start']}' and smb.lesson_time <= '{$nextReserveSlot['end']}' and smb.teacher_id = Teacher.id limit 1) IS NULL) AND 
16544                    ((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextEmergencySlot['start']}' and rs.lesson_time <= '{$nextEmergencySlot['end']}' and rs.status = 1 and rs.teacher_id = Teacher.id limit 1) IS NULL)
16545                    ) as can_emergency_lesson";
16546                $queryCondition['fields'][] = "((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextReserveSlot['start']}' and rs.lesson_time <= '{$nextReserveSlot['end']}' and rs.status = 1 and rs.user_id = {$studentId} limit 1) IS NULL) 
16547                    as student_no_next_reservation";
16548            }
16549
16550            $commonTeacherStatusParams = array(
16551                'page_display' => 'listTeacher',
16552                'query_conditions' => $queryCondition
16553            );
16554            $emergencyLessonOnair = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
16555            
16556            if (
16557                $this->isStudySapuriTosUser &&
16558                !$isReserved &&
16559                isset($emergencyLessonOnair[0]['can_emergency_lesson']) && 
16560                isset($emergencyLessonOnair[0]['student_no_next_reservation']) && 
16561                $emergencyLessonOnair[0]['can_emergency_lesson'] && # -can emergency
16562                $emergencyLessonOnair[0]['student_no_next_reservation']    # - no next reservation
16563            ) {
16564                $canEmergencyLesson = true;
16565            }
16566
16567            # ~if emergency lesson break time
16568            if ( !$isReserved && (($currentMinutes >= 26 && $currentMinutes <= 29) || ($currentMinutes >= 56 && $currentMinutes <= 59))) {
16569                $canEmergencyLesson = false;
16570                $emergencyBreakTime['status'] = true;
16571                $emergencyBreakTime['time_span'] = '['.$currentHour.'時26分 ~ '.$currentHour.'時30分]['.$currentHour.'時56分 ~ '.$currentHour.'時00分]';
16572                $emergencyBreakTime['time_return'] = '['.$currentHour.'時30分]['.$currentHour.'時00分]';
16573            }
16574        }
16575    
16576        $isAvatar = $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 || $api['CommonTeacherStatus']['Teacher']['avatar_parent_flg'] == 1 ? true : false;
16577    
16578        // lesson alert
16579        $lessonAlertMsg = [];
16580        $lessonAlertStatus = '';
16581    
16582        // if emergency lesson break time
16583        if ($isEmergencyLesson && $emergencyBreakTime['status']) {
16584            $lessonAlertMsg = [
16585                ['text' => __d('waiting','しばらくお待ちください。')],
16586                ['text' => sprintf(__d('waiting','%sの間は緊急時予約レッスンにご入室いただけません。'), $emergencyBreakTime['time_span'])],
16587                ['text' => sprintf(__d('waiting','%sまでお待ちください。'), $emergencyBreakTime['time_return'])]
16588            ];
16589            $lessonAlertStatus = 'emergency_lesson_break_time';
16590        }
16591    
16592        if (
16593            (isset($exceedDailyLimit) && $exceedDailyLimit) &&
16594            !$isReserved &&
16595            !$isAvatar
16596        ) {
16597            $lessonAlertMsg = [
16598                ['text' => __d('waiting','同一講師との連続した今すぐレッスンはレッスン完了から60分空けて再度受講が可能となります (講師の独占を緩和するため) 。')],
16599                ['text' => __d('waiting','※異なる講師を選択した場合は何度でも連続で今すぐレッスンの受講が可能です (今すぐレッスン回数無制限) 。')],
16600                ['text' => __d('waiting','※回線不具合等で短時間レッスンとなった場合は、レッスン合計時間が25分に達するまでの間は同一講師と連続で今すぐレッスンの受講が可能です。')]
16601            ];
16602            $lessonAlertStatus = 'exceed_daily_limit';
16603        }
16604    
16605        // set localize url
16606        if (
16607            isset($get['la']) && in_array($get['la'], array_flip(Configure::read('pc_allowed_currencies'))) &&
16608            $get['la'] != Configure::read('default.user_language')
16609        ) {
16610            $localizeUrl = myTools::getUrl() . '/' . $get['la'];
16611        } else {
16612            $localizeUrl = myTools::getUrl();
16613        }
16614    
16615        $displayFamilyAlert = false;
16616        if (
16617            isset($this->sharedUserData['User']['parent_id']) &&
16618            !is_null($this->sharedUserData['User']['parent_id'])
16619        ) {
16620            $parent = $this->User->find('first', array(
16621                'fields' => array(
16622                    'User.id',
16623                    'User.hash16',
16624                    'User.charge_flg'
16625                ),
16626                'conditions' => array(
16627                    'User.id' => $this->sharedUserData['User']['parent_id']
16628                ),
16629                'recursive' => -1
16630            ));
16631    
16632            if ($parent && $parent['User']['charge_flg'] != 1) {
16633                $displayFamilyAlert = true;
16634            }
16635        }
16636    
16637        $device = false;
16638        if (strpos($ua, 'Silk') !== false) {
16639            $device = 'kindle';
16640        } else if (strpos($ua, 'Android') !== false) {
16641            $device = 'andriod';
16642        } else if (strpos($ua, 'iPhone') !== false) {
16643            $device = 'ios';
16644        } else if (strpos($ua, 'iPad') !== false) {
16645            $device = 'ios';
16646        } else if (strpos($ua, 'iPod') !== false) {
16647            $device = 'ios';
16648        } else {
16649            $device = 'pc';
16650        }
16651    
16652        $corporateIndividualUser = false;
16653        $corporateTypes = Configure::read('corporate_type_arr');
16654        $corporateTypeUserTable = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
16655        if (isset($user['User']['corporate_id'])) {
16656            $corporateAdminPaymentMethod = $this->Corporate->getPaymentMethod($user['User']['corporate_id']);
16657            $corporateIndividualUser = $corporateAdminPaymentMethod == 1 ? true : false;
16658        }
16659    
16660        if (
16661            !$this->isStudySapuriUser &&
16662            $lessonType == Configure::read('lesson.type.reservation') &&
16663            ($uOnair && $uOnair['leave_lesson']) # - already left the reserved lesson
16664        ) {
16665            $isReservedCanLessonViewing = true;
16666        }
16667    
16668        $showTakeBusinessTestModal = false;
16669        if (isset($user['User']['corporate_id'])) {
16670            $showTakeBusinessTestModal = false;
16671            $isTakenBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_flg'])) ? $user['User']['monthly_speaking_business_attended_flg'] : 0;
16672            $isMustTakeBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_must_flg'])) ? $user['User']['monthly_speaking_business_attended_must_flg'] : 0;
16673            $corporateUserDate = time();
16674            $twentyPlusDayOfTheMonth = strtotime(date('Y-m-20'));
16675    
16676            if (
16677                ($isTakenBusinessTestFlg == 0 && $isMustTakeBusinessTestFlg == 1) &&
16678                !$isReserved &&
16679                (
16680                    $corporateUserDate >= $twentyPlusDayOfTheMonth ||
16681                    (
16682                        $userAdminFlag == 1 ||
16683                        (
16684                            isset($user["User"]["nickname"]) &&
16685                            strpos(strtoupper($user["User"]["nickname"]), '%%%TEST%%%') !== false
16686                        )
16687                    )
16688                )
16689            ) {
16690                $showTakeBusinessTestModal = true;
16691            }
16692        }        
16693    
16694        $liveLessonText = $liveData->lesson_flg ? __d('waiting','予約レッスン(LIVE)へ進む') : __d('waiting','予約レッスンへ進む');
16695        $button = $buttonStates[$stateButton];
16696    
16697        if(!$isGuestViewer) {
16698            $json = array_merge($json, [
16699                'button' => $button,
16700                'canDoLive' => $canDoLive,
16701                'canEmergencyLesson' => $canEmergencyLesson,
16702                'canLesson' => $canLesson,
16703                'canLessonTextbook' => $canLessonTextbook,
16704                'canMidwayLesson' => $canMidwayLesson,
16705                'checkBadge' => $checkBadge,
16706                'commonTeacher2' => $commonTeacher2,
16707                'corporateIndividualUser' => $corporateIndividualUser,
16708                'corporatePlanName' => isset($corporateTypeUserTable) ? (isset($corporateTypes[$corporateTypeUserTable]) ? $corporateTypes[$corporateTypeUserTable] : '') : '',
16709                'corporateType' => $corporateType,
16710                'corporateUserFlg' => $corporateUserFlg,
16711                'corpLightCondition' => $corpLightCondition1,
16712                'device' => $device,
16713                'displayFamilyAlert' => $displayFamilyAlert,
16714                'dummyLessonRoom' => $hasLessonBeforeActualTime,
16715                'emergencyBreakTime' => $emergencyBreakTime,
16716                'exceedDailyLimit' => isset($exceedDailyLimit) ? $exceedDailyLimit : false,
16717                'hasLessonBeforeActualTime' => $hasLessonBeforeActualTime,
16718                'homeFlg' => $api['CommonTeacherStatus']['Teacher']['home_flg'],
16719                'isAvatar' => $isAvatar,
16720                'isBusy' => $isBusy,
16721                'isEmergencyLesson' => $isEmergencyLesson,
16722                'isNormalLitePlanUser' => $isNormalLitePlanUser,
16723                'isRedLamp' => $isRedLamp,
16724                'isReserved' => $isReserved,
16725                'isReservedCanLessonViewing' => $isReservedCanLessonViewing,
16726                'isReservedCanSuddenLesson' => $isReservedCanSuddenLesson,
16727                'isStudySapuriTosUser' => $this->isStudySapuriUser,
16728                'isViewer' => $isViewer,
16729                'lessonAlertMsg' => $lessonAlertMsg,
16730                'lessonAlertStatus' => $lessonAlertStatus,
16731                'lessonOnOther' => $lessonOnOther,
16732                'lessonOrangeButtonRemaining' => $lessonOrangeButtonRemaining,
16733                'lessonType' => $lessonType,
16734                'liveData' => $liveData,
16735                'liveLessonFlg' => $liveLessonFlg ?? null,
16736                'liveLessonText' => $liveLessonText,
16737                'liveStatus' => $liveStatus,
16738                'localizeUrl' => $localizeUrl,
16739                'membershipTypeBlueBtn' => $membershipTypeBlueBtn,
16740                'membershipTypeReservationOnly' => $membershipTypeReservationOnly,
16741                'oOnair' => $oOnair,
16742                'uOnair' => $uOnair,
16743                'onGoingLesson' => $onGoingLesson,
16744                'paymentPlanId' => $user['User']['payment_plan_id'],
16745                'points' => $this->UsersPoint->getCurrentUserPoint($studentId),
16746                'redirectPlanUrl' => $redirectPlanUrl,
16747                'reservedLessonData' => $reservedLessonData,
16748                'sapuriCoin' => $sapuriCoin,
16749                'scheduleReservationData' => $scheduleReservationData,
16750                'showLoader' => $showLoader,
16751                'showNativeSpeakerWarning' => $showNativeSpeakerWarning,
16752                'showTakeBusinessTestModal' => $showTakeBusinessTestModal,
16753                'stateButton' => $stateButton,
16754                'stateButtonApi' => $api['teacher']['state_button'],
16755                'studentId' => $studentId,
16756                'suddenLessonFlg' => $suddenLessonFlg,
16757                'teacherAvatarFlg' => $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 ? true : false,
16758                'teacherLeaveNotice' => $teacherLeaveNotice,
16759                'teacherStatus' => $teacherStatus,
16760                'teacherStatusApi' => $_teacherStatus,
16761                'teacherStatusColor' => $teacherStatusColor,
16762                'textbookForReservationOnly' => $textbookForReservationOnly,
16763                'unverifiedSMS' => $stateButton == 7 ? true : false,
16764                'unsupportedBrowser' => $unsupportedBrowser,
16765                'use7DaysTrialModal' => $use7DaysTrialModal,
16766                'userAdminFlag' => $userAdminFlag,
16767                'userDoubleCheckFlag' => $userDoubleCheckFlag,
16768                'userDuplicateLesson' => $userDuplicateLesson,
16769                'userFailFlag' => $userFailFlag,
16770                'userMembershipType' => $this->userMembershipType,
16771                'userNativeOption' => $user['User']['native_option'],
16772                'userNotEligible' => $userNotEligible
16773            ]);
16774
16775            if($membershipTypeReservationOnly) {
16776                $json['lessonStartBtnText'] = __d('waiting','予約専用です');
16777            }
16778
16779            if($suddenLessonFlg) {
16780                if($use7DaysTrialModal) {
16781                    $json['suddenLessonStatus'] = 'use7DaysTrialModal';
16782                } else if (!empty(trim($redirectPlanUrl))) {
16783                    $json['suddenLessonStatus'] = 'redirectPlanUrl';
16784                } else if ($showNativeSpeakerWarning) {
16785                    $json['suddenLessonStatus'] = 'showNativeSpeakerWarning';
16786                } else if ($unsupportedBrowser) {
16787                    $json['suddenLessonStatus'] = 'unsupportedBrowser';
16788                } else if (!$canLessonTextbook) {
16789                    $json['suddenLessonStatus'] = 'cannotLessonTextbook';
16790                } else if (!empty($teacherLeaveNotice)) {
16791                    $json['suddenLessonStatus'] = 'teacherLeaveNotice';    
16792                }
16793
16794                if(!empty($json['suddenLessonStatus'])) {
16795                    $json['validateSuddenLessonFlg'] = false;
16796                } else {
16797                    $json['validateSuddenLessonFlg'] = true;
16798                }
16799            }
16800            
16801        } else if ($isViewer || $isGuestViewer) {
16802            $json = array_merge($json, [
16803                'canLesson' => $canLesson
16804            ]);
16805        }
16806
16807        if($env != 'PRODUCTION') {
16808            $json['api'] = $api;
16809            $json['commonTeacher2'] = $commonTeacher2;
16810            $json['emergencyLessonOnair'] = $emergencyLessonOnair;
16811            $json['tmpLessonOnAir'] = $tmp;
16812        }
16813    
16814        return json_encode($json);
16815    }
16816
16817    public function checkLessonStartButtonCounselor() {
16818        $this->autoRender = false;
16819        $this->layout = false;
16820        $userId = $this->Auth->user('id');
16821
16822        // if api token is not set
16823        if (empty($this->sharedUserData['User']['api_token'])) {
16824            $userApiToken = $this->User->generateAndSaveApiToken($userId);
16825            $this->Session->write('Auth.User.api_token', $userApiToken);
16826        }
16827
16828        myTools::initializeApiTunnel(array('TeachersCounselorDetailController'));
16829        $TeachersCounselorDetailController = new TeachersCounselorDetailController();
16830        $TeachersCounselorDetailController->params = [
16831            'nc_terminal_type' => 1, // pc
16832            'users_api_token' => $this->Auth->user('api_token'),
16833            'app_version' => Configure::read('max_sudden_lesson_counselor.app_version.2'),
16834            'device_type' => 2
16835        ];
16836        
16837        $data = json_decode($TeachersCounselorDetailController->counselorDetail(), true);
16838        $teacherId = $data['available_teacher'] ?? '';
16839        $status = $data['teacher']['status'] ?? '';
16840        $exceedDailyLimit = $data['exceed_daily_limit'] ? 1 : 0;
16841
16842        if ($status == 3) {
16843            $status = 2;
16844        } elseif ($status == 4) {
16845            $status = 3;
16846        }
16847
16848        return json_encode(
16849            array(
16850                'user_id' => $userId,
16851                'teacher_id' => $teacherId,
16852                'status' => $status,
16853                'exceed_daily_limit' => $exceedDailyLimit        
16854            )
16855        );
16856        
16857    }
16858
16859    public function checkLessonStartButtonCS() {
16860        $this->autoRender = false;
16861        $this->layout = false;
16862        $userId = $this->Auth->user('id');
16863        
16864        // if api token is not set
16865        if (empty($this->sharedUserData['User']['api_token'])) {
16866            $userApiToken = $this->User->generateAndSaveApiToken($userId);
16867            $this->Session->write('Auth.User.api_token', $userApiToken);
16868        }
16869
16870        myTools::initializeApiTunnel(array('TeachersCounselorDetailController'));
16871        $TeachersCounselorDetailController = new TeachersCounselorDetailController();
16872        $TeachersCounselorDetailController->params = [
16873            'nc_terminal_type' => 1, // pc
16874            'users_api_token' => $this->Auth->user('api_token'),
16875            'app_version' => Configure::read('max_sudden_lesson_counselor.app_version.2'),
16876            'device_type' => 2
16877        ];
16878
16879        if($this->userMembershipType === 12) {
16880            $csParams = array(
16881                'user_id' => $userId,
16882                'user_data' => $this->sharedUserData['User'],
16883                'customer_support_flg' => 1
16884            );
16885
16886            $data = json_decode( $this->LessonOnair->checkCounselorTeacherButtonStatus($csParams), true);
16887            $status = $data['res'] ?? '';
16888        } else {
16889            $data = json_decode($TeachersCounselorDetailController->customerSupportDetail(), true);
16890            $status = $data['teacher']['status'] ?? '';
16891        }
16892
16893        $teacherId = $data['available_teacher'] ?? '';
16894        $exceedDailyLimit = !empty($data['exceed_daily_limit']) ? 1 : 0;
16895
16896        if ($status == 3) {
16897            $status = 2;
16898        } elseif ($status == 4) {
16899            $status = 3;
16900        }
16901
16902        // Check if user exceeds daily limit for customer support lessons
16903        if ($userId) {
16904            $csList = $this->Teacher->getCustomerSupportTeachers();
16905            $csExceedLimitCheck = $this->LessonOnairsLog->checkExceedCSLimit($userId, $csList['customerSupportId']);
16906            if ($csExceedLimitCheck) {
16907                $exceedDailyLimit = 1;
16908                $status = 0;
16909            }
16910        }
16911
16912        return json_encode([
16913            'user_id' => $userId,
16914            'teacher_id' => $teacherId,
16915            'status' => $status,
16916            'exceed_daily_limit' => $exceedDailyLimit,
16917            'membership_type' => $this->userMembershipType
16918        ]);
16919    }
16920    public function updateLessonSystemTrouble() {
16921        $this->autoRender = false;
16922        $this->layout = false;
16923        $troubleResponse = false;
16924
16925        if ($this->request->is('ajax')) {
16926            $chatHash = $this->request->data['chat_hash'] ?? '';
16927            $status = $this->request->data['status'] ?? 0;
16928            $teacherID = $this->request->data['teacher_id'] ?? null;
16929            $storeMemcache = $this->request->data['store_memcache'] ?? 0;
16930
16931            if ($storeMemcache && $chatHash) {
16932                $memcached = new myMemcached();
16933                // $memcached->set(array(
16934                //     'key' => 'hide_connection_modal_flg_'.$teacherID.'-'.$chatHash,
16935                //     'value' => 1,
16936                //     'expire' => 86400 //-- 24hrs
16937                // ));
16938                $troubleResponse = true;
16939                $this->log("successfully added memcache");
16940            }
16941        }
16942
16943        return json_encode(array('result' => $troubleResponse));
16944    }
16945    
16946    public function setAppreciationModalFinish(){
16947        $this->autoRender = false;
16948        $this->layout = false;
16949
16950        if(empty($this->request->data['chat_hash'])){
16951            return false;
16952        }
16953
16954        $chat_hash = $this->request->data['chat_hash'];
16955
16956        if (!class_exists('myMemcached')) {
16957            App::uses('myMemcached', 'Lib');
16958        }
16959        $memcached = new myMemcached();
16960        $memcached->set(array(
16961            'key' => "appreciation_done_".$chat_hash,
16962            'value' => 1,
16963            'expire' => 86400 // 1 day
16964        ));
16965
16966        return true;
16967    }
16968}